如何用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
相关产品推荐
相关产品推荐

