重学React(一)-- useState

欢迎大家关注我的掘金

Hook 简介

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
Hook 是 React 实现组件逻辑的重要方式,可以用来操作 state,定义副作用,更支持开发者自定义 Hooks。Hooks 借鉴自函数式编程,但同时在使用上也有一些限制。

最常用的Hook

react中最常用的hook,肯定是useState,当然也是react文档介绍的第一个Hook。
关于文档本文就不过多的介绍了,我们从@types/react 这个包中去看

image.png

先看第一个接口类型 useState函数接受一个参数,可以是一个值,也可以是一个有返回值的函数。
大家平常的用法可能是如下:

function App (props) {
    const [name, setName] = useState('帅哥')
    reutrn <>{name}</>
}

这是绝大部分的state使用场景,那为什么react要设计useState接收一个函数作为参数呢?大家可能忽略了这部分的文档,我们来看看文档怎么说:
image.png
这是什么意思呢,简单解释下,当我们的useState初始值需要依赖一个纯函数的时候,可以使用这种方法去提高性能,举一个例子,如果一个state初始值是斐波那契数列,页面性能是肉眼可见的下降,而且每次函数组建的重绘,都会导致斐波那契数列函数的重新执行。

const [state, setState] = useState(fibonacci(40))

这种时候就可以使用惰性初始化了,示例如下:

const [state, setState] = useState(() => fibonacci(40))

useState内部会处理() => fibonacci(40)函数,并且只会执行一次。

OK,参数部分我们搞清楚了,再来看看useState的返回值类型:
[S, Dispatch<SetStateAction<S>>]这个也很好理解,一个是state,一个是state的dispatch函数。
我们再来看看Dispatch和SetStateAction的定义:

// Unlike the class component setState, the updates are not allowed to be partial
type SetStateAction<S> = S | ((prevState: S) => S);
// this technically does accept a second argument, but it's already under a deprecation warning
// and it's not even released so probably better to not define it.
type Dispatch<A> = (value: A) => void;

也就是说 useState hook返回的数组第二项是一个dispatch函数,他接受两种类型的参数,一种是newState,一种是参数为prevState,返回值为newState的函数。
第一种大家比较熟悉了,第二种大家可能不是特别熟悉,尤其是像我这种小白,为什么需要第二种呢.

image.png
贴了一个简单的代码实现,感兴趣的话大家可以试一下,使用JS触发2次按钮的点击时间,我们期望的结果是count增加2,但是对于第一种方法,其实只加了1。其实是因为在调用 state 更新函数后,组件的更新是异步的,不会马上执行;在 React 18 里,更是为更新 state 加入了自动批处理功能,多个 state 更新函数调用会被合并到一次重新渲染中。这个功能从框架上就保证了 state 变化触发渲染时的性能,但也带来一个问题,只有在下次渲染时 state 变量才会更新为最新值,如果希望每次更新 state 时都要基于当前 state 值做计算,那么这个计算的基准值有可能已经过时了。

这时函数参数的作用就体现出来了,可以保证更新函数使用最新的 state 来计算新 state 值。
useState 是 React 最常用的 Hook,理解这个 Hook 对理解其他 Hooks 很有帮助。

文章目录