You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useEffect监听keydown事件页面首次加载失效问题排查

问题分析与修复方案

核心问题

  1. keyPress函数依赖缺失:函数内部用到了ids但未加入useCallback的依赖数组,导致API加载完视频ID后,keyPress仍引用旧的空数组,判断逻辑失效。
  2. URL更新逻辑存在异步问题:调用setUrl后直接使用url赋值iframe的src,但setUrl是异步操作,此时url还是旧值,无法正确切换视频。
  3. 边界条件判断错误:原逻辑中count >= ids.length的判断不符合索引规则(视频ID数组索引从0开始,最后一个元素的索引是ids.length - 1),导致最后一个视频播放时按'e'键不会触发切换。

修复步骤

1. 修正keyPress函数的依赖与判断逻辑

将ids加入useCallback的依赖数组,同时调整边界判断条件,并且增加空数组判断避免无效操作:

const keyPress = useCallback((e) => {
  if (e.key === magicKey) {
    // 无视频ID时直接返回
    if (ids.length === 0) return;
    // 播放到最后一个视频时重置count
    if (count >= ids.length - 1) {
      setCount(0);
    } else {
      setCount(cCount => cCount + 1);
    }
  }
}, [count, ids, magicKey]);

2. 修复URL更新的useEffect

直接使用计算后的新URL赋值,避免异步状态更新的问题,同时增加边界判断:

useEffect(() => {
  // 无视频ID或count越界时不执行
  if (ids.length === 0 || count >= ids.length) return;
  const newUrl = baseUrl(ids[count]);
  setUrl(newUrl);
  const videoFrame = document.getElementById('screen');
  if (videoFrame) {
    videoFrame.src = newUrl;
  }
}, [ids, count]);

3. 优化初始状态

将url的初始值设为空字符串,避免加载无效的YouTube嵌入链接:

const [url, setUrl] = useState('');

完整修复后的代码

import React, { useEffect, useState, useCallback } from "react";
import { shuffle } from "../utils/shuffle";
import './player.css';

const baseUrl = (id) => `https://www.youtube.com/embed/${id}?autoplay=1`;
const magicKey = 'e';

function Player({ searchTerm }) {
  const [ids, setIds] = useState([]); // youtube video ids
  const [url, setUrl] = useState('');
  const [count, setCount] = useState(0);

  // Play next video when pressing 'e'
  const keyPress = useCallback((e) => {
    if (e.key === magicKey) {
      if (ids.length === 0) return;
      if (count >= ids.length - 1) {
        setCount(0);
      } else {
        setCount(cCount => cCount + 1);
      }
    }
  }, [count, ids, magicKey]);

  useEffect(() => {
    document.addEventListener("keydown", keyPress);
    return () => document.removeEventListener("keydown", keyPress);
  }, [keyPress]);

  // fetch new ids from backend based on new searchTerm
  useEffect(() => {
    console.log('api call for new ids: ', searchTerm);
    fetch(`http://localhost:4000/videos?term=${searchTerm}`)
      .then((response) => response.json())
      .then((res) => {
        setIds(shuffle(res.videoIds));
        setCount(0);
      });
  }, [searchTerm]);

  // when the id's change, set a new url for the iframe to play
  useEffect(() => {
    if (ids.length === 0 || count >= ids.length) return;
    const newUrl = baseUrl(ids[count]);
    setUrl(newUrl);
    const videoFrame = document.getElementById('screen');
    if (videoFrame) {
      videoFrame.src = newUrl;
    }
  }, [ids, count]);

  return (
      <section id="player">
        <iframe id="screen" title="youtube-player" src={url} allow='autoplay'></iframe>
      </section>
  );
}

export default Player;

内容的提问来源于stack exchange,提问作者UncleJerry23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:41:05