Recoil源码探索作者:吴然今天吴然带来《Recoil 源码探索》的分享,让我们一起学习共建!1.简介Recoil是facebook推出的状态解决方案。它的主要特点是:1.高性能渲染,2.通过状态生成派生值。2.特点高性能渲染在List和Canvas的第二个子组件中,如果有state需要共享,常用的方法是将state提升到最近的公共祖先节点,但是由此带来的问题是如果不做额外处理,会引起全局重新渲染。当然可以优化useMemo+immutable。另一种解决方案是使用上下文。如果想通过使用Context来解决全局渲染的问题,需要将需要共享的值放在一个单独的Context中。这样带来的问题是,如果我们的组件上有更多的状态需要共享,那么需要包装很多Provider,很难维护。Recoil带来了一个全新的概念Atom,将状态原子化,去中心化管理。Atom可以被组件更新和订阅。只要Atom更新,订阅这个Atom的组件就可以准确地重新渲染。派生值可以产生新的数据,可以被基于Atom的组件订阅,类似于Vue的计算属性。这里,更厉害的是这里的get方法还可以处理异步请求。3、核心流程源码的初始化与Redux类似。使用全局数据时,需要在根组件上包裹一个组件。在Recoil中,需要封装RecoilRoot组件。对于RecoilRoot,我们的业务代码中其实包裹了一层Context,提供了获取store中数据和更新store中数据的方法。原子态定义在Recoil中,每一个最小的状态单元(即不能从其他状态计算出来)被定义为一个Atom。对于每一个Atom,其实都是返回一个对象,包括key(这个key是从传入的option中解构出来的,需要全局唯一),并提供了get、set等方法。对于Atom,必须要有一个set方法,因为我们定义了一个原子数据,它必须要被修改,否则就没有意义。对于Atom来说,它的get方法比较简单。如果key存在,可以直接从stateMap中获取。选择器的派生值定义和Atom一样,也提供了get等方法。但是对于selector来说,可以通过Atom获取,所以set方法不是必须的。对于get方法,它也不同于Atom。选择器的get有一个额外的缓存处理。在没有缓存的情况下,会根据依赖的Atom计算出对应的值,下次缓存这个值。时,如果依赖值没有变化,可以从缓存中取值,尽可能提高性能。在Recoil中的组件订阅/更新共享值中,常见的订阅/更新钩子包括useRecoilState、useRecoilValue、useSetRecoilState。其中,useRecoilState包含另外两个。订阅值useRecoilValue中的主要调用链如下:useRecoilValue->useRecoilValueLoadable->useRecoilValueLoadable_LEGACY->subscribeToRecoilValue这里组件通过useRecoilValue(useRecoilState)使用Atom或selector,会在组件中添加一个订阅,实现通过useState,当相应的RecoilValue更新时,重新渲染组件,从而以最小的粒度更新组件。这里非常重要的是storeState.nodeToComponentSubscriptions.set方法。此方法更新由全局存储上的全局唯一键维护的订阅映射。通过这张图,在更新值的时候,可以准确的找到对应关系。这会触发forceUpdate重新渲染组件。更新值useSetRecoilState中的主要调用链如下:useSetRecoilState->setRecoilValue->queueOrPerformStateUpdate->applyActionsToStore->store.replaceState->BatcherEffect->sendEndOfBatchNotifications这个store.replaceState是在RecoilRoot中初始化store时设置的方法.其中notifyBatcherOfChange.current是在
