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

React中使用useRef存储数组无法过滤元素的问题求助

问题分析与解决

核心错误点

  1. filter方法未正确赋值
    Array.filter()是返回新数组的纯函数,不会修改原数组。你当前只是调用了filter但没有把结果赋值给items.current,所以原ref数组完全没变化。

  2. 数组长度判断错误
    你写的if(items.length === 0)是错误的,items是Ref对象,必须访问它的current属性才能拿到数组,正确写法是if(items.current.length === 0)。

  3. 对React State异步更新的误解
    你之前用State时觉得数组永远不为空,是因为State更新是异步的——调用setItems后,items不会立刻变成新值,你紧接着判断items.length拿到的还是旧状态。解决这个问题只需要用useEffect监听State变化即可。

修复方案(二选一)

方案一:继续使用useRef

修改handleAction中的删除逻辑:

function handleAction(click, toy){
  const item = items.current.find(item => item.name === toy )

  if(!item){
    setFound(`Not quite, try again!`);
    return;
  }

  if(click.x>item.left&&click.x<item.right){
    if(click.y<item.bottom&&click.y>item.top){
      setFound(`Well done! You've found Sarah's ${toy}`);
      // 关键:将filter返回的新数组赋值给current
      items.current = items.current.filter((item)=>item.name!==toy);
      console.log(items.current)
      // 修正:访问current的length
      if(items.current.length === 0){
        console.log('Winner');
        navigate("/leaderboard", {state:time});
      }
    }
  }else{
    setFound(`Not quite, try again!`);
    return;
  }
}

方案二:改用State(更符合React思维)

虽然你认为不需要渲染items,但判断数组为空触发导航的逻辑,用State配合useEffect会更可靠:

const Game = ()=>{
  // 用State替代useRef
  const [items, setItems] = useState([]);
  const [fetchError, setFetchError] = useState(null);
  const [found, setFound] = useState("");
  const [time, setTime] = useState(0);
  const navigate = useNavigate();

  useEffect(()=>{
    const fetchOptions = async()=>{
      const{data,error} = await supabase
        .from('items')
        .select();

      if(error){
        setFetchError('Could not fetch items');
        setItems([]);
      }

      if(data){
        setItems(data);
        setFetchError(null);
      }
    }
    fetchOptions();
  },[])

  // 监听items变化,为空时导航
  useEffect(() => {
    if(items.length === 0) {
      console.log('Winner');
      navigate("/leaderboard", {state:time});
    }
  }, [items, navigate, time])

  function handleAction(click, toy){
    const item = items.find(item => item.name === toy )

    if(!item){
      setFound(`Not quite, try again!`);
      return;
    }

    if(click.x>item.left&&click.x<item.right){
      if(click.y<item.bottom&&click.y>item.top){
        setFound(`Well done! You've found Sarah's ${toy}`);
        // 用函数式更新获取最新State
        setItems(prevItems => prevItems.filter(item => item.name !== toy));
      }
    }else{
      setFound(`Not quite, try again!`);
      return;
    }
  }

  // 其余return部分不变
}

关于Array.splice()的补充

你提到用splice也没生效,大概率是因为没找到正确的索引。如果想用splice替代filter,可以这样写:

const index = items.current.findIndex(item => item.name === toy);
if(index !== -1) {
  items.current.splice(index, 1); // 从index位置删除1个元素
}

splice是直接修改原数组的方法,不需要赋值,但要确保找到正确的索引。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 21:07:16