如何修复React Context配置,实现提交表单后自动触发useEffect重载表格数据
当前实现的逻辑硬伤
- Provider的生效范围是它包裹的子组件树,平级组件各自套Provider相当于搭建了互相隔离的独立通道,根本无法跨平级传值:
- 在
SymbolInput内部套的Provider,只覆盖自己组件下的表单区域,管不到作为兄弟组件的PriceUpdate - 布局组件里的Provider,自身没有从上层拿到动态值,传出去的是Context的初始默认值,接不到
SymbolInput内部自增的refreshKey PriceUpdate内部额外套的Provider,只是把自己拿到的静态值往下传给自己的子组件,对打通两个平级组件的链路没有任何作用
- 在
- 状态初始化存在笔误:
useState([0])把初始值设为数组,后续自增时会触发隐式类型转换,虽然也能产生值变化,但写法不规范 - 共享状态定义的层级不对:跨组件共享的状态必须上移到所有需要用到它的组件的共同最近父节点,不能定义在某个需要修改状态的子组件内部
正确实现的通信链路
按层级调整逻辑,不需要多余的嵌套:
- 找到同时包含
SymbolInput、PriceUpdate两个组件的最上层共同父组件,在这里定义共享的刷新状态,整个页面全局只在这一层套一次TableRefreshContext.Provider - 删掉所有子组件内部自己添加的重复Provider,避免无效嵌套
- 从Context中暴露两个能力:作为刷新标识的
refreshKey、用来修改这个标识的setRefreshKey函数 SymbolInput组件只需要在表单提交成功的回调里,调用Context传下来的setRefreshKey函数让标识自增就行,不需要自己维护状态PriceUpdate组件只需要在useEffect里监听Context传下来的refreshKey值,值变化时重新拉取数据就行
修正后的参考代码
共同父组件(全局单次套Provider)
import { useState } from 'react'; import TableRefreshContext from './context/TableRefresh'; import SymbolInput from './components/SymbolInput'; import PriceUpdate from './components/PriceUpdate'; export default function PageRoot() { const [refreshKey, setRefreshKey] = useState(0); return ( <TableRefreshContext.Provider value={{ refreshKey, setRefreshKey }}> <div className="page-wrapper"> <SymbolInput /> <PriceUpdate /> </div> </TableRefreshContext.Provider> ) }
修正后的SymbolInput组件
import { useContext } from 'react'; import TableRefreshContext from '../../../context/TableRefresh'; export default function SymbolInput() { const { control, handleSubmit } = useForm(); // 从Context取状态更新方法,不再自己维护刷新key const { setRefreshKey } = useContext(TableRefreshContext); const onSubmit = (data) => { axiosInstance .patch(URL, { stock_list: data.stock_list.map(list=>list.symbol), }) .then(() => { // 接口提交成功后触发标识自增 setRefreshKey(prev => prev + 1); }); }; return ( <form> {/* 原表单交互逻辑 */} </form> ); }
修正后的PriceUpdate组件
import { useContext, useState, useEffect } from 'react'; import TableRefreshContext from '../../../context/TableRefresh'; export function PriceUpdate() { const [data, setData] = useState([]); // 从Context取刷新标识 const { refreshKey } = useContext(TableRefreshContext); useEffect(() => { const fetchData = async () => { const response = await axiosInstance.get(URL) setData(response.data); }; fetchData(); }, [refreshKey]); return ( <div className="table-container"> <PriceUpdates data={data[0]} /> <PriceRanges data={data[0]} /> <ReturnRates data={data[1]} /> <QuickFacts data={data[2]} /> <Recommendations data={data[4]} /> <AdvancedStats data={data[3]} /> </div> ) }
优化提示:如果Provider的value传的是对象,每次父组件重渲染都会生成新的对象引用,可能触发所有消费Context的子组件无意义重渲染,可以用
useMemo对传递的value做缓存优化。
内容的提问来源于stack exchange,提问作者yung peso
相关产品推荐
相关产品推荐

