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

React组件重挂载时依赖未变但useEffect仍触发问题排查

问题原因分析
  1. props.initialValues的引用变化:即使react-query命中缓存返回相同数据内容,若fetchCaseById返回的是新对象引用(或封装的api.getCaseData存在深拷贝逻辑),React的useEffect依赖采用浅比较,会判定值发生变化,触发回调。
  2. 不必要的reset触发逻辑:第二个useEffect同时监听props.initialValues和props.isRefetching,组件重挂载时,只要initialValues引用变化,即使isRefetching为初始的false,也会执行reset(props.initialValues),覆盖Context中存储的用户修改后的表单值。
修复方案

方案1:仅在refetch完成时触发重置

调整useEffect依赖为isRefetching,并通过对比前后状态,只在refetch从执行状态变为完成状态时重置表单:

// 先实现一个获取上一轮状态的钩子
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}

// 在CaseForm组件中使用
const prevIsRefetching = usePrevious(props.isRefetching);

useEffect(() => {
  // 当isRefetching从true变为false,说明refetch完成,执行重置
  if (prevIsRefetching && !props.isRefetching) {
    reset(props.initialValues);
  }
}, [props.isRefetching, prevIsRefetching, reset, props.initialValues]);

方案2:用深比较判断是否需要重置

如果必须监听initialValues,通过深比较确认内容真的变化后再执行reset,避免引用变化导致的误触发:

// 可以用lodash的isEqual,或自己实现深比较函数
import _ from 'lodash';

useEffect(() => {
  if (!props.isRefetching) {
    const currentValues = getValues();
    // 仅当内容确实不同时才重置
    if (!_.isEqual(currentValues, props.initialValues)) {
      reset(props.initialValues);
    }
  }
}, [props.initialValues, props.isRefetching, getValues, reset]);

方案3:优化表单初始化优先级

确保useForm优先使用Context存储的表单值,同时同步refetch后的新初始值:

const { caseFormValues, setCaseFormValues } = useCaseProvider();
const prevIsRefetching = usePrevious(props.isRefetching);

// 挂载时初始化Context(仅当Context无值时)
useEffect(() => {
  if (!caseFormValues) {
    setCaseFormValues(props.initialValues);
  }
}, [caseFormValues, setCaseFormValues, props.initialValues]);

// 卸载时保存当前表单值到Context
useEffect(() => {
  return () => {
    setCaseFormValues(getValues());
  };
}, [setCaseFormValues, getValues]);

// 表单初始化优先取Context值
const {
  handleSubmit,
  control,
  reset,
  formState: { errors },
} = useForm({
  defaultValues: caseFormValues || props.initialValues,
});

// refetch完成时同步更新Context和表单
useEffect(() => {
  if (prevIsRefetching && !props.isRefetching) {
    setCaseFormValues(props.initialValues);
    reset(props.initialValues);
  }
}, [props.isRefetching, prevIsRefetching, reset, props.initialValues, setCaseFormValues]);
关键注意点
  • React useEffect的依赖是浅比较,对象/数组引用变化会被判定为值变化,需针对性处理。
  • 利用Context存储表单状态时,要明确初始化和重置的优先级,避免外部props意外覆盖用户修改。
  • 针对react-query的refetch操作,通过监听isRefetching的状态变化触发逻辑,比依赖数据引用更可靠。

内容的提问来源于stack exchange,提问作者Leff

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 07:25:40