1、概念
const [state, setState] = useState(initialState)
返回一个 state,以及更新 state 的函数。在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同。setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列。
setState(newState);
在后续的重新渲染中,useState 返回的第一个值将始终是更新后最新的 state。
2、默认值
useState 支持我们在调用的时候直接传入一个值,来指定 state 的默认值,比如这样 useState(0), useState({ a: 1 }), useState([ 1, 2 ]),还支持我们传入一个函数,来通过逻辑计算得出默认值,useState中的函数只会执行一次。
function App (props) {
const [ count, setCount ] = useState(() => {
return props.count || 0
})
return (
<div>
点击次数: { count }
<button onClick={() => { setCount(count + 1)}}>点我</button>
</div>
)
}3、函数式更新
如果新的 state 需要通过使用先前的 state 计算得出,那么可以传递一个函数给 setState。该函数将接收先前的 state,并返回一个更新后的值。下面的计数器组件示例展示了 setState 的两种用法:
function Counter () {
const [count, setCount] = useState(0)
function handleClick () {
setCount(count + 1)
}
function handleClickFn () {
setCount(prevCount => {
return prevCount + 1
})
}
return (
<>
Count: {count}
<button onClick={handleClick}>+</button>
<button onClick={handleClickFn}>+</button>
</>
)
}注意上面的代码,handleClick和handleClickFn一个是通过一个新的 state 值更新,一个是通过函数式更新返回新的 state。现在这两种写法没有任何区别,但是如果是异步更新的话,那你就要注意了,他们是有区别的,来看下面例子:
function Counter () {
const [count, setCount] = useState(0)
function handleClick () {
setTimeout(() => {
setCount(count + 1)
}, 3000)
}
function handleClickFn () {
setTimeout(() => {
setCount(prevCount => {
return prevCount + 1
})
}, 3000)
}
return (
<>
Count: {count}
<button onClick={handleClick}>+</button>
<button onClick={handleClickFn}>+</button>
</>
)
}当我设置为异步更新,点击按钮延迟到 3s 之后去调用 setCount 函数,当我快速点击按钮时,也就是说在3s多次去触发更新,但是只有一次生效,因为 count 的值是没有变化的。
当使用函数式更新 state 的时候,这种问题就没有了,因为它可以获取之前的 state 值,也就是代码中的 prevCount 每次都是最新的值。
4、多个 useState 的情况
useState 我们不可能只使用一个,当我们使用多个 useState 的时候,那 react 是如何识别哪个是哪个呢,其实很简单,它是靠第一次执行的顺序来记录的,就相当于每个组件存放 useState 的地方是一个数组,每使用一个新的 useState,就向数组中 push 一个 useState。所以,不要在循环,条件或嵌套函数中调用 useState, 确保总是在你的 React 函数的最顶层调用他们。
let index = 0
const memoizedStates = []
function useState (initialState) {
memoizedStates[index] = memoizedStates[index] || initialState
let currentIndex = index
function setState (newState) {
memoizedStates[currentIndex] = newState
render()
}
return [memoizedStates[index++], setState]
}
















