我和React Hooks玩了几个小时,我可能遇到了一个有趣的问题:使用setInterval不能按我期望的对react-native的操作
function Counter() {
const [time, setTime] = useState(0);
const r = useRef(null);
r.current = { time, setTime };
useEffect(() => {
const id = setInterval(() => {
console.log("called");
r.current.setTime(r.current.time + 1);
}, 1000);
return () => {
console.log("cleared");
clearInterval(id);
};
}, [time]);
return <Text>{time}</Text>;
}
每次time
状态更改时,以上代码应清除clearInterval
它在ReactJS
上工作正常,但在React-native
上却出现错误,提示"Callback() it's not a function"
它在Reactjs中按预期工作
https://codesandbox.io/s/z69z66kjyx
"dependencies": {
"react": "16.8.3",
"react-native": "^0.59.6",
...}
更新: 我尝试像这样使用ref,但是仍然出现相同的错误
const [time, setTime] = useState(0);
useInterval(() => {
setTime(time +1);
});
return (<Text>{time}</Text>);
}
function useInterval(callback) {
const savedCallback = useRef();
// Remember the latest function.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
let id = setInterval(()=>savedCallback.current(), delay);
return () => clearInterval(id);
});
}
答案 0 :(得分:2)
因为要通过DOM节点引用对DOM进行突变,并且DOM突变将在渲染的时间和效果对其进行更改之间更改DOM节点的外观。那么您将不需要使用useEffect
,而将要使用useLayoutEffect
useLayoutEffect
在React执行所有DOM突变后立即同步运行。
import React, {useState, useLayoutEffect,useRef} from 'react';
import { Text} from 'react-native';
const [time, setTime] = useState(0);
useInterval(() => {
setTime(time +1);
});
return (<Text>{time}</Text>);
}
function useInterval(callback) {
const savedCallback = useRef();
// Remember the latest function.
useLayoutEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useLayoutEffect(() => {
let id = setInterval(()=>{
console.log('called');
return savedCallback.current();
}, delay);
return () => {
console.log('cleared');
return clearInterval(id);
}
});
}
如果您仅使用useEffect
并收到此错误
Uncaught TypeError: callback is not a function at flushFirstCallback (scheduler.development.js:348) at flushWork (scheduler.development.js:441) at MessagePort.channel.port1.onmessage (scheduler.development.js:188)
这是RN中的一个错误,因为版本scheduler
错误,不幸的是RN并没有明确依赖雾化器的调度程序版本。 Dan Abramov 已在调度程序版本"0.14.0"
要解决此问题,只需运行以下命令
npm install scheduler@0.14.0 --save
或者尝试将"scheduler": "0.14.0"
添加到package.json
中的dependencies
中,然后重新运行包管理器
答案 1 :(得分:0)
您应该仍然可以在效果钩子中使用状态钩子变量,因为它们在范围内。
useRef:此处不会跟踪突变,因此不会触发重新渲染。
我觉得以引用方式使用refs比直接使用state和setter更为冗长。 useRef
引用用于一段时间内的可变值,但您已经通过useState
钩子获得了。 ref之所以有效,是因为您并没有真正使ref发生变化,而是在每个渲染周期中仅使用已更新 的useState
钩子的内容覆盖它。
我已经更新了沙箱,将useRef
用作您的方式,您的useEffect
钩子导致您的清理函数在每个渲染器上启动,因此删除了相关性。您会注意到,直到刷新为止,您只会看到“被叫”。