首次点击时useState钩子设置taskID返回undefined问题求助
解决useState设置taskID首次点击返回undefined的问题
我在使用useState钩子设置taskID时遇到问题:首次点击按钮会返回undefined,但刷新整个页面后就能正常运行。怀疑问题出在嵌套数组的映射方式上,代码如下:
const [task_id, setGetid] = useState('') return ( <div> {cart && Object.keys(cart).map(state => { return ( <div className='h-auto max-h-[60vh] w-[50vw] overflow-y-auto flex flex-row flex-wrap justify-center items-center mt-5 gap-4' key={cart[state]._id}> {cart[state]?.list && Object.keys(cart[state]?.list).map(task => { return ( <div className='bg-[#1c1e21] h-[6vh] w-[48vw] relative drop-shadow-md flex flex-row items-center justify-end' key={cart[state]?.list[task]?._id}> <span className='ml-5 text-white font-Poppins text-1xl absolute left-0'>{cart[state]?.list[task]?.task}</span> <form onSubmit={handleSubmit(patchHandler)}> <button type='submit' className='bg-[#01313d] text-md font-Poppins text-white drop-shadow-md h-[4vh] w-auto flex flex-row items-center pl-3 pr-3 mr-2 gap-1'> <FaEdit /> Edit </button> </form> <form onSubmit={deleteHandler}> <button type='submit' onClick={() => { setGetid(cart[state]?.list[task]?._id) // 首次点击时设置task ID返回undefined,刷新页面后可正常工作 }} className='bg-[#01313d] text-md font-Poppins text-white drop-shadow-md h-[4vh] w-auto flex flex-row items-center pl-3 pr-3 mr-2 gap-1'> <FaTrash /> Remove </button> </form> </div> ) })} </div> ) })} </div> )
问题原因
- 首次渲染时
cart数据可能未完全加载,虽然做了空值判断,但嵌套层级的cart[state]?.list[task]?._id在数据未就绪时会返回undefined。 - useState的更新是异步的,点击按钮时
onClick触发setGetid,但表单的onSubmit会立即执行,此时task_id还没更新,导致deleteHandler拿到旧值undefined。
解决方案
方案1:直接传ID给删除函数(最推荐)
不用通过useState存task ID,点击时直接把ID作为参数传给deleteHandler,绕开异步更新的问题:
<form onSubmit={(e) => { e.preventDefault(); const taskId = cart[state]?.list[task]?._id; deleteHandler(taskId); }}> <button type='submit' className='bg-[#01313d] text-md font-Poppins text-white drop-shadow-md h-[4vh] w-auto flex flex-row items-center pl-3 pr-3 mr-2 gap-1'> <FaTrash /> Remove </button> </form>
对应的删除函数修改为:
const deleteHandler = (taskId) => { if (!taskId) return; // 这里执行你的删除逻辑,比如调用API };
方案2:确保数据加载完成后再渲染
给组件加加载状态,等cart数据完全获取后再渲染列表,避免渲染未就绪的数据:
const [loading, setLoading] = useState(true); const [cart, setCart] = useState({}); // 假设这里是获取cart数据的逻辑 useEffect(() => { const fetchCart = async () => { const res = await fetch('/your-cart-api'); const data = await res.json(); setCart(data); setLoading(false); }; fetchCart(); }, []); if (loading) return <div>加载中...</div>; // 后面再渲染原来的cart列表
方案3:用useRef保存最新ID
如果一定要用useState存ID,可以搭配useRef确保删除函数能拿到最新值:
const [task_id, setGetid] = useState(''); const taskIdRef = useRef(''); // 点击时同时更新state和ref <button type='submit' onClick={() => { const id = cart[state]?.list[task]?._id; setGetid(id); taskIdRef.current = id; }}>...</button> // 删除函数里用ref的值 const deleteHandler = (e) => { e.preventDefault(); const currentId = taskIdRef.current; if (currentId) { // 执行删除逻辑 } };
内容的提问来源于stack exchange,提问作者Gino
相关产品推荐
相关产品推荐

