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

如何用Context值更新React useReducer中的状态值?

问题:React中用Context数据批量更新useReducer状态

我在构建React应用时,使用Context存储全局变量与函数。Context中的referral状态会在初始API调用完成后更新,我希望主组件中能在referral值可用时,更新useReducer的状态值。但初始时Context值尚未加载,导致直接初始化reducer状态无效。尝试用useEffect逐个调用更新的写法过于冗余,需要更简洁的实现方案。

相关代码

Context文件代码

export const CurrentUserAppProvider = ({
  children,

}) => {

  const [referral, setReferral] = useState()

  function getReferralById(referralMasterId: string) {
    return referralAxios
      .get(`/api/Referral`)
      .then(function (response) {
        setReferral(response.data)
      })
      .catch(function (error) {

      })
  }

  const appContext = {
    referral,
  }

  return (
    <AppContext.Provider value={appContext}>{children}</AppContext.Provider>
  )
}

主组件初始代码

export const ReferralDetails: React.FC<{}> = ({}) => {
  const {
    referral,
  } = useContext(AppContext)

  const [referralData, setReferralData] = useReducer(referralReducer, {
    currentAssigneeDisplayName: referral?.currentAssigneeDisplayName || '',
    currentAssigneeEmail: referral?.currentAssigneeEmail || '',
    currentAssigneeGRNID: referral?.currentAssigneeGRNID || '',
    referralMasterId: referral?.referralMasterID || null,
    reasonTypeId: referral?.reasonTypeID || '',
    referralTypeId: referral?.referralTypeID || '',
    riskDescription: referral?.riskDescription || '',
    statusTypeId: referral?.statusTypeID || 1,
  })

  function referralReducer(
    state: ReferralReducer,
    event: { name: string; value: string | number | unknown }
  ) {
    return { ...state, [event.name]: event.value }
  }

冗余的useEffect写法

useEffect(() => {
    setReferralData({
      name: 'actionStepId',
      value: referral?.actionStepID || 1,
    })
    setReferralData({
      name: 'comment',
      value: referral?.comment || '',
    })
    setReferralData({
      name: 'currentAssigneeDisplayName',
      value: referral?.currentAssigneeDisplayName || '',
    })
    setReferralData({
      name: 'currentAssigneeEmail',
      value: referral?.currentAssigneeEmail || '',
    })
    setReferralData({
      name: 'currentAssigneeGRNID',
      value: referral?.currentAssigneeGRNID || '',
    })
    setReferralData({
      name: 'referralMasterId',
      value: referral?.referralMasterID || '',
    })
    setReferralData({
      name: 'reasonTypeId',
      value: referral?.reasonTypeID || '',
    })
    setReferralData({
      name: 'referralTypeId',
      value: referral?.referralTypeID || '',
    })
    setReferralData({
      name: 'riskDescription',
      value: referral?.riskDescription || '',
    })
    setReferralData({
      name: 'statusTypeId',
      value: referral?.statusTypeID || '',
    })

  }, [ referral])

解决方案

方法1:扩展Reducer支持批量更新

修改reducer逻辑,让它能识别批量更新的动作类型,一次性覆盖所有目标字段:

// 更新reducer,支持批量初始化动作
function referralReducer(
  state: ReferralReducer,
  action: { name: string; value: any } | { type: 'INIT_FROM_REFERRAL'; payload: Partial<ReferralReducer> }
) {
  // 匹配批量更新动作
  if (action.type === 'INIT_FROM_REFERRAL') {
    return { 
      ...state, 
      ...action.payload 
    };
  }
  // 保留原有单个字段更新逻辑
  return { ...state, [action.name]: action.value };
}

然后在useEffect中一次性构建payload并调用更新:

useEffect(() => {
  if (!referral) return;
  
  setReferralData({
    type: 'INIT_FROM_REFERRAL',
    payload: {
      actionStepId: referral.actionStepID || 1,
      comment: referral.comment || '',
      currentAssigneeDisplayName: referral.currentAssigneeDisplayName || '',
      currentAssigneeEmail: referral.currentAssigneeEmail || '',
      currentAssigneeGRNID: referral.currentAssigneeGRNID || '',
      referralMasterId: referral.referralMasterID || '',
      reasonTypeId: referral.reasonTypeID || '',
      referralTypeId: referral.referralTypeID || '',
      riskDescription: referral.riskDescription || '',
      statusTypeId: referral.statusTypeID || '',
    }
  });
}, [referral]);

方法2:映射字段批量生成更新动作

如果不想修改reducer,可以通过字段映射结合循环,批量生成单个更新动作:

useEffect(() => {
  if (!referral) return;
  
  // 定义本地reducer字段与Context中referral字段的映射关系
  const fieldMap = {
    actionStepId: 'actionStepID',
    comment: 'comment',
    currentAssigneeDisplayName: 'currentAssigneeDisplayName',
    currentAssigneeEmail: 'currentAssigneeEmail',
    currentAssigneeGRNID: 'currentAssigneeGRNID',
    referralMasterId: 'referralMasterID',
    reasonTypeId: 'reasonTypeID',
    referralTypeId: 'referralTypeID',
    riskDescription: 'riskDescription',
    statusTypeId: 'statusTypeID',
  };

  // 遍历映射关系,批量调用更新
  Object.entries(fieldMap).forEach(([localKey, remoteKey]) => {
    const value = referral[remoteKey as keyof typeof referral];
    setReferralData({
      name: localKey,
      // 根据字段设置默认值
      value: value ?? (localKey === 'actionStepId' ? 1 : '')
    });
  });
}, [referral]);

额外优化:延迟初始化reducer状态

如果希望组件挂载后等待Context数据加载完成再初始化reducer状态,可以先将初始状态设为空,再通过useEffect完成初始化:

// 初始状态设为符合类型的空对象
const [referralData, setReferralData] = useReducer(referralReducer, {} as ReferralReducer);

useEffect(() => {
  if (!referral) return;
  
  // 此处使用方法1或方法2的更新逻辑
}, [referral]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:43:24