React子组件调用父组件函数时如何获取最新父组件状态?
React状态闭包陷阱:获取最新state的解决方案
问题根源
你遇到的是典型的React闭包陷阱:onRemoveGroundLease函数在组件初次渲染时被创建,捕获了当时的process状态值。后续即使process通过setProcess更新,这个函数依然持有旧的process引用,导致打印的是原始未修改的状态。
解决方法
方法一:从子组件传递最新状态数据
子组件已经持有最新的process实例,直接让子组件调用回调时传递最新的groundLeases(或整个process),父组件无需依赖自身state,直接使用传入的最新值:
- 修改父组件的回调函数签名:
const onRemoveGroundLease = (groundLease: ICloserGroundLease, latestGroundLeases: ICloserGroundLease[]) => { console.log(latestGroundLeases); // 这里是最新的groundLeases状态 const groundLeaseIds = latestGroundLeases?.map((gl) => gl.arkGroundLeaseId); if (groundLeaseIds) { const index = groundLeaseIds.indexOf(groundLease.arkGroundLeaseId); if (index > -1) { groundLeaseIds.splice(index, 1); } const payload: IProcessGroundLeaseSave = { processId: process.collateralCheckProcessId, // 若processId可能变化,也可让子组件传递整个process groundLeaseIds }; onCommonPut({ url: collateralCheckUrl.associateGroundLeases(), payload, successCallback: () => { getProcesses(process.collateralCheckProcessId); onCancelProcessEdit(); } }, ServiceEnum.COLLATERAL_API); } };
- 修改子组件的调用逻辑,传递最新数据:
frameworkComponents={{ renderDeleteAction: buildDeleteActionCell({ onDelete: (groundLease) => onRemoveGroundLease(groundLease, process.groundLeases || []) }), }}
方法二:用useRef保存最新状态
通过useRef创建一个引用,每次process更新时同步最新值到ref,回调函数直接从ref获取最新状态:
- 父组件中添加ref和同步逻辑:
const CollateralChecks : React.FC = () => { const [processes, setProcesses] = React.useState<ICollateralCheckProcess[]>([]); const [process, setProcess] = React.useState<ICollateralCheckProcess>(null); // 创建ref跟踪最新process const processRef = React.useRef<ICollateralCheckProcess>(null); // 每次process更新时同步到ref React.useEffect(() => { processRef.current = process; }, [process]); // ... 其余代码 };
- 修改
onRemoveGroundLease使用ref获取最新状态:
const onRemoveGroundLease = (groundLease: ICloserGroundLease) => { const latestProcess = processRef.current; console.log(latestProcess.groundLeases); // 最新状态 const groundLeaseIds = latestProcess.groundLeases?.map((gl) => gl.arkGroundLeaseId); if (groundLeaseIds) { const index = groundLeaseIds.indexOf(groundLease.arkGroundLeaseId); if (index > -1) { groundLeaseIds.splice(index, 1); } const payload: IProcessGroundLeaseSave = { processId: latestProcess.collateralCheckProcessId, groundLeaseIds }; onCommonPut({ url: collateralCheckUrl.associateGroundLeases(), payload, successCallback: () => { getProcesses(latestProcess.collateralCheckProcessId); onCancelProcessEdit(); } }, ServiceEnum.COLLATERAL_API); } };
方法三:用useCallback确保函数捕获最新状态
将onRemoveGroundLease用useCallback包裹,并把process加入依赖数组,这样每次process更新时,函数都会重新创建,自然捕获最新的状态:
const onRemoveGroundLease = React.useCallback((groundLease: ICloserGroundLease) => { console.log(process.groundLeases); // 最新状态 const groundLeaseIds = process.groundLeases?.map((gl) => gl.arkGroundLeaseId); if (groundLeaseIds) { const index = groundLeaseIds.indexOf(groundLease.arkGroundLeaseId); if (index > -1) { groundLeaseIds.splice(index, 1); } const payload: IProcessGroundLeaseSave = { processId: process.collateralCheckProcessId, groundLeaseIds }; onCommonPut({ url: collateralCheckUrl.associateGroundLeases(), payload, successCallback: () => { getProcesses(process.collateralCheckProcessId); onCancelProcessEdit(); } }, ServiceEnum.COLLATERAL_API); } }, [process]);
注意:这种方式会导致每次
process变化时函数重新生成,可能引发子组件重渲染。如果子组件是纯组件,可以给子组件加上React.memo优化:export default React.memo(CollateralCheckForm);
内容的提问来源于stack exchange,提问作者Conrad Addo
相关产品推荐
相关产品推荐

