如何在React组件卸载时执行代码并访问最新状态值?
React组件卸载时获取最新状态的解决方案
要实现仅在组件卸载时执行清理函数,同时访问最新的组件状态,可以通过useRef跟踪状态的最新值,结合空依赖的useEffect来实现,以下是具体方案:
方案一:使用useRef同步状态
通过useRef保存状态的最新引用,每次状态更新时同步更新ref.current,这样在卸载时的清理函数中就能访问到最新状态:
import { useState, useEffect, useRef } from 'react'; import Button from '@mui/material/Button'; const Child = () => { const [testArray, setTestArray] = useState([]); // 创建ref跟踪最新的testArray const testArrayRef = useRef(testArray); // 每次testArray更新时,同步到ref useEffect(() => { testArrayRef.current = testArray; }, [testArray]); // 空依赖的useEffect,仅在卸载时执行清理函数 useEffect(() => { return () => { // 这里能获取到卸载前的最新testArray console.log('卸载时的最新状态:', testArrayRef.current); }; }, []); const pushItem = () => { setTestArray((arr) => [...arr, { name: "just a name" }]); }; return ( <div> <Button onClick={pushItem} variant="contained"> Push Item </Button> </div> ); }; const Parent = () => { const [showChild, setShowChild] = useState(false); const toggle = () => { setShowChild(!showChild); }; return ( <div> <Button onClick={toggle} variant="contained"> Toggle </Button> <br /> <br /> <br /> {showChild ? <Child /> : "hidden"} </div> ); };
原理说明
useRef的current属性是可变的,不受React闭包捕获规则的限制,每次状态更新时我们主动将最新状态同步到ref中;- 空依赖的
useEffect只会在组件挂载时执行一次,其返回的清理函数仅在组件卸载时触发,此时ref.current已经保存了状态的最新值。
方案二:封装自定义useUnmount钩子
如果需要在多个组件中复用这个逻辑,可以封装一个自定义钩子useUnmount,同样基于useRef来确保回调能访问最新状态:
import { useState, useEffect, useRef } from 'react'; import Button from '@mui/material/Button'; // 自定义卸载钩子 const useUnmount = (callback) => { const callbackRef = useRef(callback); // 每次回调更新时,同步到ref useEffect(() => { callbackRef.current = callback; }, [callback]); // 卸载时执行最新的回调 useEffect(() => { return () => { callbackRef.current(); }; }, []); }; const Child = () => { const [testArray, setTestArray] = useState([]); // 使用自定义钩子,直接在回调中访问最新的testArray useUnmount(() => { console.log('卸载时的最新状态:', testArray); }); const pushItem = () => { setTestArray((arr) => [...arr, { name: "just a name" }]); }; return ( <div> <Button onClick={pushItem} variant="contained"> Push Item </Button> </div> ); }; // Parent组件代码不变 const Parent = () => { const [showChild, setShowChild] = useState(false); const toggle = () => { setShowChild(!showChild); }; return ( <div> <Button onClick={toggle} variant="contained"> Toggle </Button> <br /> <br /> <br /> {showChild ? <Child /> : "hidden"} </div> ); };
原理说明
- 每次组件渲染时,传入
useUnmount的回调函数会捕获当前最新的状态; callbackRef会同步保存最新的回调函数,卸载时执行这个最新的回调,自然就能访问到最新的组件状态。
内容的提问来源于stack exchange,提问作者Giannis Savvidis
相关产品推荐
相关产品推荐

