我正在尝试使用新的React钩子功能,但跌跌撞撞了。
我有一个useEffect
,它调用setInterval
,它会更新本地状态。像这样:
const [counter, setCounter] = React.useState(0);
React.useEffect(() => {
const k = setInterval(() => {
setCounter(counter + 1);
}, 1000);
return () => clearInterval(k);
}, []);
return (
<div>Counter via state: {counter}<br/></div>
);
这行不通,因为计数器是在第一次调用时捕获的,因此计数器停留在1
值上。
如果我使用refs,则会更新ref,但不会调用rerender(在UI中只会看到0值):
const counterRef = React.useRef(0);
React.useEffect(() => {
const k = setInterval(() => {
counterRef.current += 1;
}, 1000);
return () => clearInterval(k);
}, []);
return (
<div>Counter via ref: {counterRef.current}</div>
);
我可以通过组合它们来实现自己想要的东西,但实际上看起来并不正确:
const [counter, setCounter] = React.useState(0);
const counterRef = React.useRef(0);
React.useEffect(() => {
const k = setInterval(() => {
setCounter(counterRef.current + 1);
counterRef.current += 1;
}, 1000);
return () => clearInterval(k);
}, []);
return (
<div>Counter via both: {counter}</div>
);
您能告诉谁用钩子妥善处理此类案件吗?
答案 0 :(得分:1)
useRef
仅在不需要组件更新的情况下才有用。但是可以通过相同的方法解决在异步useEffect
中访问当前状态的问题,即使用对象引用而不是不可变状态:
const [state, setState] = React.useState({ counter: 0 });
React.useEffect(() => {
const k = setInterval(() => {
state.counter++;
setCounter(state);
}, 1000);
return () => clearInterval(k);
}, []);
在React社区中不建议使用可变状态,因为它比不可变状态具有更多的缺点。
与类组件中的setState
一样,状态更新程序功能可用于在状态更新期间获取当前状态:
const [counter, setCounter] = React.useState(0);
React.useEffect(() => {
const k = setInterval(() => {
setCounter(conter => counter + 1);
}, 1000);
return () => clearInterval(k);
}, []);
或者,setTimeout
可用于每秒设置新间隔:
React.useEffect(() => {
const k = setTimeout(() => {
setCounter(counter + 1);
}, 1000);
return () => clearInterval(k);
}, [counter]);
答案 1 :(得分:1)
到目前为止,我已经几次遇到这种情况了,我更喜欢的解决方案是使用useReducer
而不是useState
,就像这样:
const [counter, dispatch] = React.useReducer((state = 0, action) => {
// better declared outside of the component
if (action.type === 'add') return state + 1
return state
});
React.useEffect(() => {
const k = setInterval(() => {
dispatch({ type: 'add' });
}, 1000);
return () => clearInterval(k);
}, []);
return (
<div>Counter via state: {counter}<br/></div>
);
尽管添加了一些样板,但实际上简化了“何时考虑我的变量?”。 更多https://reactjs.org/docs/hooks-reference.html#usereducer