React中使用useRef存储数组无法过滤元素的问题求助
问题分析与解决
核心错误点
filter方法未正确赋值Array.filter()是返回新数组的纯函数,不会修改原数组。你当前只是调用了filter但没有把结果赋值给items.current,所以原ref数组完全没变化。数组长度判断错误
你写的if(items.length === 0)是错误的,items是Ref对象,必须访问它的current属性才能拿到数组,正确写法是if(items.current.length === 0)。对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
相关产品推荐
相关产品推荐

