React 微状态管理库

61 阅读4分钟

1.什么是微状态管理库(micro state management)

在React中,state是可以用来展示在UI(用户接口)中的数据,React负责根据state渲染组件到用户的屏幕上。局部的state目前在React中依靠hooks来设置和管理,那么在一个大的应用中global state该怎么管理呢,这就需要状态管理库了。

不同应用对global state的需求是不一样的,比如一个处理服务器状态的app只需要一个或很少几个global state,而如果是一个有很多图表的app,每个图表里的每一行可能都会有一个state,对global state管理的需求自然也就会很多,这就需要我们去设计符合应用场景的尽可能轻量级的global state(全局状态)管理方案,这也是文章标题“微状态”中“微”的意思。

一个基础的状态管理库需要做到这几点:读取state,更新state,根据state渲染。而现在社区里的状态管理库会各自有不同的附加功能:优化re-render,集成其他系统,异步支持等,但天上不会掉馅饼,这些支持显然不是无消耗的(free),所以一个微状态管理器应该是只集成某一些我们需要的功能,而不是一个大而全的状态管理库(像Redux这类)。

2.React hooks的state

有几种常用的React hooks,useState可以创建一个local state,useReducer和useState类似,useEffect可以让我们在React完成渲染程序之后执行逻辑操作等副作用(side Effect),这使得我们可以通过React组件生命周期实现一些特性。

hooks现在十分流行的原因是,他可以让我们把逻辑操作从UI组件里抽离出来,比如这样一个useState的例子:

const Component = () => {
    const [count, setCount] = useState(0);
    return (
        {count} setCount((c) => c + 1)}>+1
    );
};

如果我们想把逻辑操作从里面抽离出来该怎么办呢:

const useCount = () => { 
    const [count, setCount] = useState(0);
    return [count, setCount];
};

const Component = () => {
    const [count, setCount] = useCount();
    return (
        {count} setCount((c) => c + 1)}> +1
    );
};

看起来可能没什么改变,但这样做有两个优点:

(1)有了明确的名字useCount

(2)Component组件不掺和useCount的执行

第一条的优点是在我们定义一个自定义hook时,增加了可读性,我们可以自己设定一个名字,看到名字就知道这个hook干什么用的。 第二条的优点在于,在useCount被提取出Component之后,我们可以在不影响Component的情况下改变useCount的功能。我们在useCount中添加console或者加useEffect都不会影响到Component

逻辑和UI组件独立的意义是很重大的,这让我们可以自定义许多hook,我们可以在www.npmjs.com/search?q=re… 或者 github.com/search?q=re…

中找到数万个社区创造的hooks

3.为什么React Component应该是纯函数

我们写出来的组件应该是一个可以复用的单元集合,如果我们想要一个组件可以被很多地方重复使用、同时重复使用多次输出都不会改变,那么就需要这个组件是一个纯函数。如果一个组件的执行结果依赖于外部state,在外部state改变时输出结果也改变,那么会产生很多问题。

4.什么时候使用global state

有如下两条规则:

(1)需要跨组件传递props

如果我们有一个祖父组件,一个父组件,一个子组件。当要从祖父组件传递到子组件props时,如果要逐级传,需要祖父->父->孙这样传递,这就导致props改变时父组件也要触发re-render,产生了不必要的开销,此时用global state可以优化性能。

(2)React之外的变量

当一个变量本身并不存在于React中,而是从外部获取的,我们就可以把它作为一个global state。比如要对用户信息进行鉴权,后端传递过来了这个用户的登录信息,这个信息作为React之外的state,就可以用作global state。自定义一个鉴权hook,鉴权成功就返回true,使用时把这个hook放进React中。