为什么使用 React Hooks useState() 的计数会在两个数字之间交替?
Why does a count using React Hooks useState() alternate between two numbers?
以下是使用useState()
的React Hooks实验。它工作正常,除非单击 +
按钮,然后数字可以从 7001
和 7000
交替,然后在一些数字之间快速闪烁。
实际上,在不点击 +
的情况下,数字表现良好,但达到大约 8000 或 9000,然后它可能会开始在某些数字之间闪烁。为什么会这样,如何解决?
P.S. 初步调试发现: Counter()
好像被调用了多次,每次都设置了一个Interval Timer。所以 "magically",似乎 useState()
运行 只有一次——出于某种未知的神奇原因——或者它可能 运行 不止一次,但只是返回了完全相同的内容每次都是为了某种神奇的机制。 0
的初值还真是第一次这样。当它在未来的时候是 useState(0)
时,count
不是 0
...要么。
function Counter() {
const [count, setCount] = React.useState(0);
setInterval(() => {
setCount(count + 1000);
}, 1000);
return (
<div>
<button onClick={() => setCount(count + 1)}> + </button>
{ count }
<button onClick={() => setCount(count - 1)}> - </button>
</div>
);
}
ReactDOM.render(<Counter />, document.querySelector("#root"));
button { margin: 0 1em }
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
对 'why is that' 不太确定,但已通过在按钮中替换 setCount(c => c + 1)
和在间隔中替换 setCount(c => c + 1000)
来解决。
将'setInterval'放在一个效果中也确保只有一个间隔...
React.useEffect(() => {
setInterval(() => {
setCount(c => c + 1000);
}, 1000);
},[])
PS Counter()
在每次渲染时都会被调用,我认为...而 useState
每次安装只被调用一次.
- 功能组件中的代码在每次重新渲染组件时都会执行。因此,在每次重新渲染时,您都会启动一个无限计时器,该计时器每秒增加 1000 来计数
- 每次您更改组件的状态时,React 都会重新渲染它。意思是,每次执行
setCount
都会导致新的重新渲染并启动新的计时器
- 此外,
setCount
是异步的,如果您需要依赖前一个状态来确定下一个状态,您应该调用回调,就像在其他答案中演示的那样 (setCount(c => c + 1)
)
这样的事情应该有效:
import React, {useState, useRef, useEffect} from 'react';
function Counter() {
const [count, setCount] = useState(0);
//useRef gives us an object to store things between re-renders
const timer = useRef();
useEffect(() => {
timer.current = setInterval(() => {
setCount(count => count + 1000);
}, 1000);
//If we return a function, it will be called when component is dismounted
return () => {
clearInterval(timer.current);
}
}, []);
return (
<div>
<button onClick={() => setCount(count => count + 1)}> + </button>
{ count }
<button onClick={() => setCount(count => count - 1)}> - </button>
</div>
);
}
以下是使用useState()
的React Hooks实验。它工作正常,除非单击 +
按钮,然后数字可以从 7001
和 7000
交替,然后在一些数字之间快速闪烁。
实际上,在不点击 +
的情况下,数字表现良好,但达到大约 8000 或 9000,然后它可能会开始在某些数字之间闪烁。为什么会这样,如何解决?
P.S. 初步调试发现: Counter()
好像被调用了多次,每次都设置了一个Interval Timer。所以 "magically",似乎 useState()
运行 只有一次——出于某种未知的神奇原因——或者它可能 运行 不止一次,但只是返回了完全相同的内容每次都是为了某种神奇的机制。 0
的初值还真是第一次这样。当它在未来的时候是 useState(0)
时,count
不是 0
...要么。
function Counter() {
const [count, setCount] = React.useState(0);
setInterval(() => {
setCount(count + 1000);
}, 1000);
return (
<div>
<button onClick={() => setCount(count + 1)}> + </button>
{ count }
<button onClick={() => setCount(count - 1)}> - </button>
</div>
);
}
ReactDOM.render(<Counter />, document.querySelector("#root"));
button { margin: 0 1em }
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
对 'why is that' 不太确定,但已通过在按钮中替换 setCount(c => c + 1)
和在间隔中替换 setCount(c => c + 1000)
来解决。
将'setInterval'放在一个效果中也确保只有一个间隔...
React.useEffect(() => {
setInterval(() => {
setCount(c => c + 1000);
}, 1000);
},[])
PS Counter()
在每次渲染时都会被调用,我认为...而 useState
每次安装只被调用一次.
- 功能组件中的代码在每次重新渲染组件时都会执行。因此,在每次重新渲染时,您都会启动一个无限计时器,该计时器每秒增加 1000 来计数
- 每次您更改组件的状态时,React 都会重新渲染它。意思是,每次执行
setCount
都会导致新的重新渲染并启动新的计时器 - 此外,
setCount
是异步的,如果您需要依赖前一个状态来确定下一个状态,您应该调用回调,就像在其他答案中演示的那样 (setCount(c => c + 1)
)
这样的事情应该有效:
import React, {useState, useRef, useEffect} from 'react';
function Counter() {
const [count, setCount] = useState(0);
//useRef gives us an object to store things between re-renders
const timer = useRef();
useEffect(() => {
timer.current = setInterval(() => {
setCount(count => count + 1000);
}, 1000);
//If we return a function, it will be called when component is dismounted
return () => {
clearInterval(timer.current);
}
}, []);
return (
<div>
<button onClick={() => setCount(count => count + 1)}> + </button>
{ count }
<button onClick={() => setCount(count => count - 1)}> - </button>
</div>
);
}