如何从React子组件更新Context并解决更新后子组件不重渲染问题
问题原因及修复方案
你修改后子组件不触发重渲染,90%的概率是以下两种问题导致:
- 子组件取值逻辑未同步修改:调整后的Context返回值是包含
corporateContext和setCorporateContext的对象,如果你还是按之前的逻辑直接从Context取属性,会一直拿到undefined,自然不会触发更新。 - 更新Context时没有返回新对象:React的state更新是浅比较,如果你修改原state对象再返回,对象引用没有变化,Provider会判定值未更新,不会触发子组件重渲染。
完整正确实现代码
import React, { createContext, useContext, useState, useEffect } from 'react'; // TS项目可先定义Context类型,避免后续取值错误 interface CorporateContextType { corporateContext: { corporateId: string; corporateRole: string; corporateAdmin: boolean; corporateSuperAdmin: boolean; } | undefined; setCorporateContext: React.Dispatch<React.SetStateAction<CorporateContextType['corporateContext']>>; } const CorporateContext = createContext<CorporateContextType>({ corporateContext: undefined, setCorporateContext: () => {}, }); // 自定义取值Hook export const useCorporateContext = () => useContext(CorporateContext); export const CorporateProvider = ({ children }) => { const [corporateContext, setCorporateContext] = useState<CorporateContextType['corporateContext']>(undefined); useEffect(() => { const localStorageSet = !!localStorage.getItem('corporateDetailsSet'); if (localStorageSet) { setCorporateContext({ corporateId: localStorage.getItem('corporateId') || '', corporateRole: localStorage.getItem('corporateRole') || '', corporateAdmin: localStorage.getItem('corporateAdmin') === 'true', corporateSuperAdmin: localStorage.getItem('corporateSuperAdmin') === 'true', }); } else { (async () => { try { const json = await fetchCorporateUserDetails(getClientSideJwtTokenCookie()); if (json.success !== true) { console.log('json invalid'); return; } // 先构造新的Context对象,避免异步state的坑 const newContextVal = { corporateId: json.data.corporate_id, corporateRole: json.data.corporate_role, corporateAdmin: json.data.corporate_role == 'Admin', corporateSuperAdmin: json.data.corporate_super_admin, }; setCorporateContext(newContextVal); // 直接传入新构造的对象,不要用state变量,此时state还未更新 addCorporateDetailsToLocalStorage(newContextVal); } catch (e) { console.log(e.message); } })(); } }, []); return ( <CorporateContext.Provider value={{ corporateContext, setCorporateContext }}> {children} </CorporateContext.Provider> ); }; export default CorporateProvider;
子组件正确用法示例
const DemoChild = () => { // 正确解构Context返回的两个属性 const { corporateContext, setCorporateContext } = useCorporateContext(); const updateRole = () => { // 更新时必须返回全新对象,不能直接修改原state setCorporateContext(prev => { if (!prev) return prev; return { ...prev, corporateRole: 'Admin', corporateAdmin: true } }) } return ( <div> <p>当前企业ID:{corporateContext?.corporateId}</p> <p>当前角色:{corporateContext?.corporateRole}</p> <button onClick={updateRole}>升级为管理员</button> </div> ) }
额外注意点
你原有代码中setCorporateUserData后直接调用addCorporateDetailsToLocalStorage(corporateUserData)存在隐患:React的state更新是异步的,刚调用set方法后拿到的state还是旧值,直接存储会导致本地缓存和实际Context值不一致。
内容的提问来源于stack exchange,提问作者Denis2310
相关产品推荐
相关产品推荐

