You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 10:05:32