React自定义useSignup钩子请求数据后state值未更新如何解决
问题根源
- 你观测到的「state未更新」属于误判:React的状态更新是异步批量执行的,
finally块中访问的msg、status是当前渲染闭包内的旧值,并非状态没有更新,下次组件重渲染时就可以拿到最新的状态值。 - 不需要使用
useEffect发起请求:这个自定义hook的核心是按需触发注册逻辑,直接在需要发起注册的场景(比如表单提交回调)手动调用暴露的registerUser方法即可,自然不会出现导入hook就自动触发请求的问题。 - 现有代码混用
async/await和.then/.catch写法存在冗余,且loading初始值设置不合理,无请求时默认状态不应为加载中。
修正后代码
import axios from 'axios' import { useState } from 'react' export const useSignup = () => { // 初始无请求,loading默认设为false const [loading, setLoading] = useState(false) const [status, setStatus] = useState(false) const [msg, setMsg] = useState('') const registerUser = async (emailAddress, password) => { // 发起请求前重置状态、开启加载 setLoading(true) setStatus(false) setMsg('') try { // 统一使用async/await写法,避免逻辑混乱 const res = await axios.post('/signup', { emailAddress, password, }) setStatus(res?.data.success) setMsg(res?.data.msg) } catch (err) { if (err?.response) { setStatus(err.response.data.success) setMsg(err.response.data.msg) } else { setStatus(false) setMsg('Error Occured') } console.error(err) } finally { setLoading(false) } } return { loading, status, msg, registerUser } }
组件使用示例
不需要添加useEffect,按需调用方法即可:
import { useSignup } from './useSignup' const SignupForm = () => { const { loading, status, msg, registerUser } = useSignup() // 若需要观测状态变化,可在此处添加effect监听 // useEffect(() => { // console.log('最新状态:', msg, status, loading) // }, [msg, status, loading]) const handleSubmit = (e) => { e.preventDefault() const email = e.target.email.value const password = e.target.password.value registerUser(email, password) } return ( <form onSubmit={handleSubmit}> <input name="email" type="email" required placeholder="邮箱" /> <input name="password" type="password" required placeholder="密码" /> <button type="submit" disabled={loading}> {loading ? '注册中' : '注册'} </button> {msg && <p>{msg}</p>} </form> ) }
内容的提问来源于stack exchange,提问作者Vicky
相关产品推荐
相关产品推荐

