Hooks 是 React 16 中的特性,解决函数组件想使用类组件的一些特性。
关于更多 Hooks 介绍,请参考 React 官网[1]
useState
之前是在类组件中使用状态通过 state 定义,大概代码是这样的。
import React from 'react';
class Counter extends React.Component {
state = {
number: 0
}
handleClick = () => {
this.setState({
number: this.state.number + 1
})
}
render() {
return (
<>
<p>{this.state.number}</p>
<button
onClick={ this.handleClick }>
改数字
</button>
</>
);
}
}
function render() {
ReactDOM.render(<Counter />, document.getElementById('root'));
}
render()
但是函数组件没有实例,也没有状态。函数组件使用状态需要使用 useState
钩子。
关于 useState
的用法是,需要传入一个参数作为状态的初始值,当函数执行后会返回两个值,一个是当前状态的属性,一个是修改状态的方法。
我们通过一个计数器的例子,当点击按钮表示状态加1。
import React, {useState} from 'react';
function Counter() {
const [
number,
setNumber
] = useState(0)
return (
<>
<p>{number}</p>
<button
onClick={
() => setNumber(number + 1)
}
>
改数字
</button>
</>
)
}
function render() {
ReactDOM.render(<Counter />, document.getElementById('root'));
}
render()
现在我们已经掌握了它的用法,那么我们开始分析它的原理。
原理
我们需要写一个 useState
方法,会返回当前状态的属性和设置状态的方法,每当状态改变之后,方法中会调用刷新视图的 render
方法。
let memoizedState;
function useState (initialState) {
memoizedState = memoizedState || initialState
function setState (newState) {
memoizedState = newState
render()
}
return [memoizedState, setState]
}
再次尝试之前的代码,依然可以正常使用,但是当多个 useState
存在的时候就有问题了,只能变一个状态了。
function Counter() {
const [
number,
setNumber
] = useState(0)
const [
title,
setTitle
] = useState('随机标题')
return (
<>
<h1>{title}</h1>
<p>{number}</p>
<button
onClick={
() => setNumber(number + 1)
}
>
改数字
</button>
<button
onClick={
() => setTitle(`随机标题${Math.random()}`)
}
>
改标题
</button>
</>
)
}
现在我们需要优化我们的 Hooks ,解决多个 useState
同时使用的问题,当多个状态存在的时候,我们需要使用数组保存状态。
let memoizedStates = []
let index = 0
function useState (initialState) {
memoizedStates[index] = memoizedStates[index] || initialState
let currentIndex = index
function setState (newState) {
memoizedStates[currentIndex] = newState
render()
}
return [memoizedStates[index++], setState]
}
function Counter() {
const [
number,
setNumber
] = useState(0)
const [
title,
setTitle
] = useState('随机标题')
return (
<>
<h1>{title}</h1>
<p>{number}</p>
<button
onClick={
() => setNumber(number + 1)
}
>
改数字
</button>
<button
onClick={
() => setTitle(`随机标题${Math.random()}`)
}
>
改标题
</button>
</>
)
}
function render() {
index = 0
ReactDOM.render(<Counter />, document.getElementById('root'));
}
render()
现在已经完成了 useState
的基本原理,当你了解原理之后,使用 Hooks 就变得更加容易了。
References
[1]
React 官网: https://reactjs.org/docs/hooks-state.html