单一 useEffect 中的 React 钩子状态
React hooks state in single useEffect
我正在尝试使用新的 React hooks 功能,但遇到了一些问题。
我有一个 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 会更新,但不会调用重新渲染(在 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>
);
请问谁能用hooks妥善处理这种情况?
useRef
仅在不需要组件更新的情况下才有用。但是在异步 useEffect
中访问当前状态的问题可以用相同的方法解决,即使用对象引用而不是不可变状态:
const [state, setState] = React.useState({ counter: 0 });
React.useEffect(() => {
const k = setInterval(() => {
state.counter++;
setCounter(state);
}, 1000);
return () => clearInterval(k);
}, []);
React 社区不鼓励使用可变状态,因为它比不可变状态有更多缺点。
与 class 组件中的 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]);
我已经遇到过几次这种情况,我的首选解决方案是使用 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>
);
虽然添加了一些样板,但它确实简化了 "when is my variable taken in account ?"。
更多内容 https://reactjs.org/docs/hooks-reference.html#usereducer
我正在尝试使用新的 React hooks 功能,但遇到了一些问题。
我有一个 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 会更新,但不会调用重新渲染(在 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>
);
请问谁能用hooks妥善处理这种情况?
useRef
仅在不需要组件更新的情况下才有用。但是在异步 useEffect
中访问当前状态的问题可以用相同的方法解决,即使用对象引用而不是不可变状态:
const [state, setState] = React.useState({ counter: 0 });
React.useEffect(() => {
const k = setInterval(() => {
state.counter++;
setCounter(state);
}, 1000);
return () => clearInterval(k);
}, []);
React 社区不鼓励使用可变状态,因为它比不可变状态有更多缺点。
与 class 组件中的 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]);
我已经遇到过几次这种情况,我的首选解决方案是使用 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>
);
虽然添加了一些样板,但它确实简化了 "when is my variable taken in account ?"。 更多内容 https://reactjs.org/docs/hooks-reference.html#usereducer