为何首次点击Submit时代码返回空数组,二次提交才正常?
问题原因与解决方案
这是React里非常常见的useState异步更新特性导致的问题,我来给你讲清楚为啥会这样,以及怎么解决:
为什么首次点击会输出空数组?
React的useState状态更新是异步批量处理的,当你在onSubmit里调用setValues(data)时,React并不会立刻更新values的状态,而是把这个更新请求加入到更新队列中,等到当前渲染周期结束后,才会统一处理队列里的更新、更新组件状态并重新渲染。
所以你在setValues(data)之后立刻console.log(values),拿到的其实还是更新前的旧状态(也就是初始的空数组)。第二次点击时,values已经是第一次提交的结果了,这时候打印的就是上一次的正确数据,看起来像是“正常”了,但其实逻辑还是有问题的。
两种解决办法
办法1:直接使用表单提交的data参数
如果你只是需要在提交时打印或处理最新的表单数据,完全没必要等values状态更新,直接用onSubmit函数里的data参数就行,它就是实时的最新数据:
function App() { const {handleSubmit, register} = useForm() const [values, setValues] = useState([]) const onSubmit = (data) => { setValues(data) console.log(data) // 直接用data,而不是values } return ( <div className="App"> <form onSubmit={handleSubmit(onSubmit)}> <label>Enter Your Name</label> <input name='name' type='text' ref={register} placeholder='Name'/> <label>I'm a : </label> <select name="role" ref={register}> <option value="student">Student</option> <option value="teacher">Teacher</option> </select> <button type='submit'>Submit</button> </form> </div> ); }
办法2:用useEffect监听values的变化
如果你确实需要在values状态更新完成后执行某些操作(比如根据新值发起请求),可以使用useEffect钩子,把values加入依赖数组,这样每次values更新后都会触发回调:
import { useState, useEffect } from 'react'; import { useForm } from 'react-hook-form'; function App() { const {handleSubmit, register} = useForm() const [values, setValues] = useState([]) // 监听values变化,更新后执行操作 useEffect(() => { if (Object.keys(values).length > 0) { // 避免初始空数组触发 console.log(values) // 这里可以放需要在values更新后执行的逻辑 } }, [values]) const onSubmit = (data) => { setValues(data) } return ( <div className="App"> <form onSubmit={handleSubmit(onSubmit)}> <label>Enter Your Name</label> <input name='name' type='text' ref={register} placeholder='Name'/> <label>I'm a : </label> <select name="role" ref={register}> <option value="student">Student</option> <option value="teacher">Teacher</option> </select> <button type='submit'>Submit</button> </form> </div> ); }
总结
记住React的状态更新是异步的,不要在调用状态更新函数(比如setValues)之后立刻去读取状态值,要么直接用更新时的数据源(比如这里的data),要么用useEffect监听状态变化来处理后续逻辑。
内容的提问来源于stack exchange,提问作者Kiko
相关产品推荐
相关产品推荐

