React Context Provider更新后组件函数内值未同步问题
React Context状态更新后组件函数内值未同步的解决方案
问题分析
- Provider内console.log未更新:
setCompany是异步操作,调用后立即访问company状态拿到的仍是更新前的旧值,这是React状态更新的异步特性导致的。 - 组件handlePickerChange获取旧ID:回调函数因闭包捕获了旧的
company引用,或回调未随company更新而重新创建,导致触发时使用旧数据。
具体修复步骤
1. 修复Provider的状态日志问题
将状态更新后的日志逻辑移至监听company变化的useEffect中,确保获取最新状态:
export const CompanyProvider: React.FC<CompanyProviderProps> = ({ children, }) => { const { companyId } = useParams(); const [company, setCompany] = useState<EntrepriseReceiveInterface | null>( null ); const [loading, setLoading] = useState<boolean>(true); if (!companyId) { return <h1>Erreur</h1>; } const getCompanyUnique = EntrepriseGetByIdUseCase(companyId); useEffect(() => { if (getCompanyUnique.status === "success") { const body = getCompanyUnique.data.body; console.log("body", body); setCompany(body); setLoading(false); } }, [getCompanyUnique.status, companyId]); // 监听company变化,打印最新值 useEffect(() => { console.log("company(最新)", company); }, [company]); return ( <CompanyContext.Provider value={{ company, setCompany }}> {loading ? <div>Chargement...</div> : children} </CompanyContext.Provider> ); };
2. 修复组件回调的旧值问题
使用useCallback包裹回调函数,确保其随company更新而重新创建,捕获最新状态:
const { company, setCompany } = useCompany(); if (!company) { return <h1>Erreur</h1>; } const { mutate: setColorMutation } = useEditCompanyColor(); console.log("company", company._id); // 用useCallback包裹,依赖项包含所有外部引用 const handlePickerChange = useCallback((color: any) => { console.log(company._id); setColorMutation( { entrepriseId: company._id, color: color.hex }, { onSuccess: () => { setCompany((prevCompany) => prevCompany ? { ...prevCompany, colorPrimary: color.hex } : null ); toast.success("Vous avez bien changé la couleur primaire", { style: { borderColor: "var(--successHexa)" }, }); }, onError: () => { toast.error("Une erreur est survenue, veuillez réessayer", { style: { borderColor: "var(--errorHexa)" }, }); }, } ); }, [company, setColorMutation, setCompany]); return ( <Card className="flex justify-between items-center h-full"> <CardHeader> <CardTitle>Couleur - Entreprise</CardTitle> <CardDescription>Choisissez votre couleur d'entreprise</CardDescription> </CardHeader> <CardContent className="flex flex-col xl:flex-row p-0 pt-2 pb-2 pr-6 xl:pt-0 xl:pb-0 items-center space-x-2"> <div className="text-2xl font-bold rounded-full w-16 h-16" style={{ backgroundColor: company.colorPrimary }} ></div> {company._id} <Compact color={company.colorPrimary} onChange={handlePickerChange} /> </CardContent> </Card> );
关键原理总结
- React状态更新是异步的,不能在调用
setState后立即获取新状态,需通过useEffect监听状态变化。 - 依赖外部状态的组件回调,必须用
useCallback包裹并设置完整依赖项,避免闭包捕获旧值导致逻辑错误。
内容的提问来源于stack exchange,提问作者Thomas Ribalta
相关产品推荐
相关产品推荐

