为什么useState调用setState传入回调会抛出不支持第二个参数的错误
遗漏的知识点
- 类组件与函数组件的状态更新API存在设计差异:类组件的
setState方法支持传入第二个回调参数,会在状态更新、组件完成重渲染后执行,但函数组件中useState返回的状态更新函数不支持该回调参数,你传入的回调函数不会被执行,因此会触发官方警告。 - 函数组件的每个渲染周期都对应独立的状态快照,你调用
setErrMsg后,当前作用域内的errMsg仍为本次渲染的旧值,即使直接打印也无法获取到更新后的值。 - 函数组件中,官方规定所有需要在状态更新后执行的副作用逻辑,都需要通过
useEffectHook声明实现。
解决方法
方案1:用useEffect监听状态变化(对应原回调需求)
如果你的逻辑必须依赖状态更新完成、组件重渲染后的最新值,就在组件主体中新增useEffect监听errMsg的变化:
import { useState, useRef, useEffect } from 'react'; // 记得导入useEffect function Register(props) { const [errMsg, setErrMsg] = useState(null); const fullNameInputRef = useRef(); const emailInputRef = useRef(); const passwordInputRef = useRef(); // 新增useEffect监听errMsg变化 useEffect(() => { // 可添加判断避免初始化时触发不需要的逻辑 if (errMsg) { console.log(errMsg); // 其他需要在errMsg更新后执行的逻辑都可以放在这里 } }, [errMsg]); // 依赖项填errMsg,仅当errMsg发生变化时才执行该effect function submitHandler(event) { event.preventDefault(); const enteredFullName = fullNameInputRef.current.value; const enteredEmail= emailInputRef.current.value; const enteredPassword = passwordInputRef.current.value; axios({ method: 'post', url: 'http://localhost:3000/api/users/register', data: { username: enteredFullName, email: enteredEmail, password: enteredPassword } }).then( (res) => { if (res.data.success == false) { // 移除原来的第二个回调参数,直接传要更新的值即可 setErrMsg(`${res.data.message}`); } else { console.log(res)} }).catch( (err) => { console.log(err) setErrMsg("An error has occured. Please try again later") }); } // ...组件其他渲染逻辑 }
方案2:直接复用待更新的值(轻量场景更高效)
如果你只是需要使用即将设置给errMsg的新值,不需要等组件重渲染,可以直接把值存为变量复用,不需要新增useEffect:
// axios.then分支内的代码 if (res.data.success == false) { const newErrMsg = `${res.data.message}`; setErrMsg(newErrMsg); // 直接使用新值即可 console.log(newErrMsg); }
内容的提问来源于stack exchange,提问作者Sher Mi
相关产品推荐
相关产品推荐

