setCount(prev => prev + 1) 和 setCount(count + 1) 有什么区别?

Dor*_*mon 3 reactjs

我正在阅读 React hooks 的示例。我发现他们写

setCount(count + 1)
Run Code Online (Sandbox Code Playgroud)

但我通常这样写

setCount(prev => prev + 1)
Run Code Online (Sandbox Code Playgroud)

有什么区别吗?哪一个更好?

Zac*_*ber 8

有一个区别,首先,由于函数中的闭包,计数将基于渲染发生时的当前值。

第二个将始终使用最新的增量值。

由于闭包是一个复杂的主题,因此这里有一些示例。第一个显示了两者之间的主要区别。

第二个示例展示了几种使闭包和效果/钩子能够正常工作的方法

const { useState, useEffect } = React;
function Example(){
const [count1, setCount1] = useState(0);
useEffect(()=>{
  setCount1(count1 + 1);
  setCount1(count1 + 1);
  setCount1(count1 + 1);
},[])

const [count2, setCount2] = useState(0);
useEffect(()=>{
  setCount2(prev=> prev + 1);
  setCount2(prev=> prev + 1);
  setCount2(prev=> prev + 1);
},[])
return <div>
Both count1 and count2 have had 3 increments.
<br/>
count1 stays at 1 because the count1 variable in the useEffect isn't change due to the closure in the arrow function in the useEffect
<br/>
Current count1: {count1}
<br/>
Current count2: {count2}
</div>
}
ReactDOM.render(<Example/>,document.getElementById('root'))
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
Run Code Online (Sandbox Code Playgroud)

const { useState, useEffect, useRef } = React;
function Example(){
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const [count3, setCount3] = useState(0);

const count3Ref = useRef(count3);
count3Ref.current = count3;

useEffect(()=>{
  const id = setInterval(()=>{
  setCount1(count1+1);
  setCount2(prev=>prev+1);
  setCount3(count3Ref.current+1);
  },300)
  return ()=>{clearInterval(id)}
},[])

const [count4, setCount4] = useState(0);
useEffect(()=>{
  const id = setTimeout(()=>{
  setCount4(count4+1);
  },300)
  return ()=>{clearTimeout(id)}
},[count4])
return <div>
All of the counts theoretically increment every 300ms
<br/>
<br/>
count1 stays at 1 because the count1 variable in the useEffect isn't change due to the closure in the arrow function in the useEffect
<br/>

Current count1: {count1}
<hr/>
count2 uses the functional version of setCount2 so it always uses the latest version and will update properly
<br/>
Current count2: {count2}
<hr/>
count3 increments because refs are mutable by nature and allow us to bypass the closure.
<br/>
Current count3: {count3}
<hr/>
Another possiblity: count4 increments because we properly use the dependency array and force the useEffect to re-run every time count4 changes.
<br/>
Current count4: {count4}

</div>
}
ReactDOM.render(<Example/>,document.getElementById('root'))
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
Run Code Online (Sandbox Code Playgroud)