React library 快速入门——Recoil

792 阅读2分钟

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

介绍

Recoil是React的一个轻量且高性能状态管理库,它的目标是解决一下几个问题:

  • 组件间的状态共享只能通过将 state 提升至它们的公共祖先来实现,但这样做可能导致重新渲染一颗巨大的组件树。
  • Context 只能存储单一值,无法存储多个各自拥有消费者的值的集合。
  • 以上两种方式都很难将组件树的顶层(state 必须存在的地方)与叶子组件 (使用 state 的地方) 进行代码分割。

快速上手

在介绍它的api之前我们先看一下应用在项目中应用Recoil是有多么简单:

  • 首先是引入RecoilRoot并将其放在根组件的位置(也可以放在其他父组件位置上)
import {RecoilRoot} from 'recoil';
...
<RecoilRoot>
   <App />
</RecoilRoot>
  • 设置公共状态:atom store.js
export const cloudClassSpuState = atom<number>({
    key: 'cloudClassSpuState', 
    default: 702 
});

一个公共状态可以用一个atom表示

  • 使用和修改公共状态:useRecoilState
import { cloudClassSpuState} from '../store.js';
import {useRecoilState} from 'recoil';
...
export default function StudyRoom() {
    const [cloudClassSpu, setSpu] = useRecoilState<number>(cloudClassSpuState);
    return <div>{cloudClassSpu}</div>
}

useRecoilState返回的是一个数组,第一个值是公共状态,第二个值就是对这个公共状态的修改方法,调用这个方法后其他有依赖到这个状态的组件自动会进行更新。

以上就是Recoil的级别用法了,核心的api就是atomuseRecoilState

其他常用api

  • selectoruseRecoilValue selector表示派生状态,类似于vue中的computed,
const todoListStatsState = selector({
  key: 'todoListStatsState',
  get: ({get}) => {
    const todoList = get(todoListState);
    const totalNum = todoList.length;
    const totalCompletedNum = todoList.filter((item) => item.isComplete).length;
    const totalUncompletedNum = totalNum - totalCompletedNum;
    const percentCompleted = totalNum === 0 ? 0 : totalCompletedNum / totalNum * 100;

    return {
      totalNum,
      totalCompletedNum,
      totalUncompletedNum,
      percentCompleted,
    };
  },
});

而要使用selector则需要useRecoilValue

function TodoListStats() {
  const {
    totalNum,
    totalCompletedNum,
    totalUncompletedNum,
    percentCompleted,
  } = useRecoilValue(todoListStatsState);

  const formattedPercentCompleted = Math.round(percentCompleted);

  return (
    <ul>
      <li>Total items: {totalNum}</li>
      <li>Items completed: {totalCompletedNum}</li>
      <li>Items not completed: {totalUncompletedNum}</li>
      <li>Percent completed: {formattedPercentCompleted}</li>
    </ul>
  );
}

这里在定义selector的时候只设置了get而没有设置set,因此这个selector是只读的

另外selector的get可以返回一个promise,在获取selector中值的时候会等待这个promise吐出结果,这就是异步selector

  • useSetRecoilState 当使用useRecoilState获取状态时,组件也同时会订阅该状态,一旦发生变更就会进行更新,但是有些组件仅仅需要进行状态的修改而不需要渲染该状态,这时候就可以用这个api
import { useSetRecoilState} from 'recoil';
import {infoState} from '../store';

function form() {
  const setInfoState = useSetRecoilState(infoState);\
  return (
      <button onClick={() => setInfoState({end:false})}>set info</button>
)

  • useResetRecoilState 这个api可以将某个state重设为默认值,比如用在表单的重置按钮上

  • useRecoilStateLoadable 这个api可以读取异步selector,并返回一个Loadable 对象,可以从这个对象中获知值是否在加载中、已完成、出错。

掌握以上这些常用api就可以在项目中启用recoil了,相比redux,这个库对状态的管理和组织更为灵活。