Cut*_*ter 4 javascript react-native react-hooks
我有一个屏幕组件,它有一个getPosition()按时间间隔每秒调用一次的函数。
如果stopRace()调用该函数或者用户按下物理/图形后退按钮,我想清除此间隔,以便它不会继续在后台运行。
为此,我尝试将间隔 ID 存储在raceUpdateInterval状态变量中。
然后我clearInterval(raceUpdateInterval)在stopRace()函数和cleanup()函数中使用清除这个间隔。
当我调用该stopRace()函数,然后按返回时,间隔被清除。我知道这一点是因为我的控制台记录:
Still Running
Still Running
Still Running
Reached cleanup function
Run Code Online (Sandbox Code Playgroud)
但是,如果我按后退按钮,间隔不会清除。相反,我的控制台记录:
Still Running
Still Running
Still Running
Reached cleanup function
Still Running
Run Code Online (Sandbox Code Playgroud)
随后是包含以下建议的内存泄漏警告:
To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function
Run Code Online (Sandbox Code Playgroud)
这正是我想要做的,但由于某种超出我理解的原因而不起作用。
这是该组件的相关代码:
const RaceScreen = ({route, navigation}) => {
const [raceUpdateInterval, setRaceUpdateInterval] = useState(0);
useEffect(function() {
return function cleanup() {
console.log('Reached cleanup function')
clearInterval(raceUpdateInterval)
}
}, []);
function getPosition(){
console.log("Still being called")
//get position
}
function startRace(){
setRaceUpdateInterval(setInterval(getPosition, 1000))
}
function stopRace(){
clearInterval(raceUpdateInterval)
}
Run Code Online (Sandbox Code Playgroud)
为什么stopRace()函数可以正确清除间隔,但cleanup()函数却不能?
您的代码可能无法正常工作的部分原因是,如果您运行startRace多次运行该函数而中间没有停止它,则间隔将再次启动,但间隔 ID 将丢失。
它未能清除的主要原因是,当使用 [] 作为依赖数组的 useEffect 看到时,它在开始时看到的 raceUpdateInterval 是:0。它没有看到更新的值的原因是因为 useEffect 在它运行(和重新运行)的点上创建了一个闭包。因此,您需要使用引用来使其访问最新版本的 raceUpdateInterval
以下是我将如何修改您的代码以使其正常工作。不要在函数中启动计时器,而是使用useEffect来启动副作用,这样就永远不会出现计时器无法清理的情况。
我使用 ref 将函数添加到区间,因为我不知道 getPosition 函数中有多少个闭包变量。这样,positionFunctRef.current 始终指向函数的最新版本,而不是保持静态。
const RaceScreen = ({ route, navigation }) => {
const [runningTimer, setRunningTimer] = useState(false);
function getPosition() {
console.log('Still being called');
//get position
}
const positionFunctRef = useRef(getPosition);
useEffect(() => {
positionFunctRef.current = positionFunctRef;
});
useEffect(
function () {
if (!runningTimer) {
return;
}
const intervalId = setInterval(() => {
positionFunctRef.current();
}, 1000);
return () => {
console.log('Reached cleanup function');
clearInterval(intervalId);
};
},
[runningTimer]
);
function startRace() {
setRunningTimer(true);
}
function stopRace() {
setRunningTimer(false);
}
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4826 次 |
| 最近记录: |