React-Query useMutation onError中console.log(email)输出空值问题
React-Query useMutation onError打印email为空的问题解决
问题原因
- 执行顺序偏差:请求失败后,React-Query会优先触发
onError回调,之后才会更新isError状态并触发对应的useEffect。所以onError执行时,setEmail("hi isError")还未执行,email仍是初始空字符串。 - 闭包陷阱:即使
setEmail提前执行,onError回调是组件初次渲染时创建的,它捕获的是当时的email值(空字符串);状态更新后组件重新渲染,但旧的onError函数不会更新,依然拿不到新状态。
解决方案
方案一:直接在onError中处理状态与打印
不需要依赖isError的useEffect,直接在onError里完成状态设置和打印,彻底避免执行顺序问题:
export const googleLogin = (data: any) => { return axios.post("/login/google", data).then(({ data }) => data as any); }; const [email, setEmail] = useState<string>(""); const { mutate, isLoading, isError } = useMutation(googleLogin, { onError(error: AxiosError) { const newEmail = "hi isError"; setEmail(newEmail); console.log(newEmail); // 直接使用要设置的变量,无需依赖state }, }); function handleSocialLogin(event: React.MouseEvent<HTMLElement> & any) { mutate({ clientIp: "hi", }); } return <button onClick={handleSocialLogin}>button</button>;
方案二:用useRef跟踪最新状态
如果必须保留useEffect的逻辑,可通过useRef存储最新的email值,避开闭包陷阱:
export const googleLogin = (data: any) => { return axios.post("/login/google", data).then(({ data }) => data as any); }; const [email, setEmail] = useState<string>(""); const emailRef = useRef<string>(""); // 同步state到ref,确保ref始终持有最新值 useEffect(() => { emailRef.current = email; }, [email]); const { mutate, isLoading, isError } = useMutation(googleLogin, { onError(error: AxiosError) { // 延迟执行,确保isError的useEffect已完成状态更新 setTimeout(() => { console.log(emailRef.current); }, 0); }, }); useEffect(() => { if (isError) { setEmail("hi isError"); } }, [isError]); function handleSocialLogin(event: React.MouseEvent<HTMLElement> & any) { mutate({ clientIp: "hi", }); } return <button onClick={handleSocialLogin}>button</button>;
方案三:在isError的useEffect中完成打印
如果逻辑必须通过监听isError来设置状态,那么打印操作应该放在同一个useEffect里,确保状态更新后立即执行:
export const googleLogin = (data: any) => { return axios.post("/login/google", data).then(({ data }) => data as any); }; const [email, setEmail] = useState<string>(""); const { mutate, isLoading, isError } = useMutation(googleLogin); useEffect(() => { if (isError) { const newEmail = "hi isError"; setEmail(newEmail); console.log(newEmail); // 直接使用变量,或在下一次渲染时打印email } }, [isError]); function handleSocialLogin(event: React.MouseEvent<HTMLElement> & any) { mutate({ clientIp: "hi", }); } return <button onClick={handleSocialLogin}>button</button>;
内容的提问来源于stack exchange,提问作者김민수
相关产品推荐
相关产品推荐

