React中如何监听自定义hook返回的response变化?最佳实践探讨
针对你的问题,这里有几种实用的解决方案:
1. 直接用返回的response状态做UI反馈(最省事)
useSubmit已经把请求结果存在response状态里了,你可以直接在组件里根据它的值渲染提示,比如成功/错误消息:
// 表单组件代码 const { isLoading, response, submit } = useSubmit(); const formik = useFormik({ initialValues: { firstName: "" }, onSubmit: (values) => { submit("", values); }, }); // 用useEffect处理响应后的副作用(比如重置表单、自动清除提示) useEffect(() => { if (!response) return; // 显示提示(可以换成你项目里的弹窗组件) alert(response.message); // 成功后重置表单 if (response.type === "success") { formik.resetForm(); } // 3秒后清除响应状态,避免提示一直显示 const timer = setTimeout(() => { // 这里需要给useSubmit加个清除方法:在useSubmit里添加const clearResponse = () => setResponse(null);并返回 // clearResponse(); }, 3000); return () => clearTimeout(timer); }, [response, formik]); return ( <form onSubmit={formik.handleSubmit}> <input name="firstName" value={formik.values.firstName} onChange={formik.handleChange} /> <button type="submit" disabled={isLoading}> {isLoading ? "提交中..." : "提交"} </button> {/* 直接渲染响应提示 */} {response && ( <div className={`alert ${response.type}`}> {response.message} </div> )} </form> );
这种方式完全利用React的状态更新机制,适合只需要展示UI反馈的场景。
2. 优化useSubmit让submit返回Promise(更灵活)
当前的submit是异步函数但没返回结果,我们可以修改它,让它直接返回成功响应或抛出错误,这样在Formik的onSubmit里就能直接await处理,不用依赖response状态:
修改后的useSubmit:
import { useState } from "react"; const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const useSubmit = () => { const [isLoading, setLoading] = useState(false); const [response, setResponse] = useState(null); const submit = async (url, data) => { const random = Math.random(); setLoading(true); try { await wait(2000); if (random < 0.5) throw new Error("Something went wrong"); const successRes = { type: "success", message: `Thanks for your submission ${data.firstName}, we will get back to you shortly!`, }; setResponse(successRes); return successRes; // 返回成功结果 } catch (err) { const errorRes = { type: "error", message: "Something went wrong, please try again later!", }; setResponse(errorRes); throw errorRes; // 抛出错误结果 } finally { setLoading(false); } }; const clearResponse = () => setResponse(null); // 新增清除响应的方法 return { isLoading, response, submit, clearResponse }; }; export default useSubmit;
然后在表单组件里使用:
const { isLoading, submit, clearResponse } = useSubmit(); const formik = useFormik({ initialValues: { firstName: "" }, onSubmit: async (values) => { try { const res = await submit("", values); alert(res.message); formik.resetForm(); setTimeout(clearResponse, 3000); } catch (err) { alert(err.message); setTimeout(clearResponse, 3000); } }, });
这种方式更符合异步代码的常规写法,逻辑都集中在提交的回调里,不用额外监听状态变化,也避免了多次提交时状态被覆盖的问题。
关于useEffect的使用场景
如果需要在response变化时执行一些额外的副作用(比如发送统计埋点、跳转页面),那用useEffect监听是合理的。但如果只是处理提交后的结果反馈,方案2的Promise方式会更直接,代码逻辑更清晰。
注意用useEffect的时候,一定要把所有用到的依赖项(比如formik、response)都加到依赖数组里,避免出现闭包陷阱。
内容的提问来源于stack exchange,提问作者bryan noriega miguel
相关产品推荐
相关产品推荐

