react 哲学_细聊Concent & Recoil , 探索react数据流的新开发模式

11dc499d6641e1ac480f334f1828da40.png

开源不易,感谢你的支持,❤ star me if you like concent ^_^

序言

之前发表了一篇文章 redux、mobx、concent特性大比拼, 看后生如何对局前辈,吸引了不少感兴趣的小伙伴入群开始了解和使用 concent,并获得了很多正向的反馈,实实在在的帮助他们提高了开发体验,群里人数虽然还很少,但大家热情高涨,技术讨论氛围浓厚,对很多新鲜技术都有保持一定的敏感度,如上个月开始逐渐被提及得越来越多的出自facebook的最新状态管理方案 recoil,虽然还处于实验状态,但是相必大家已经私底下开始欲欲跃试了,毕竟出生名门,有fb背书,一定会大放异彩。

不过当我体验完recoil后,我对其中标榜的精确更新保持了怀疑态度,有一些误导的嫌疑,这一点下文会单独分析,是否属于误导读者在读完本文后自然可以得出结论,总之本文主要是分析ConcentRecoil的代码风格差异性,并探讨它们对我们将来的开发模式有何新的影响,以及思维上需要做什么样的转变。

数据流方案之3大流派

目前主流的数据流方案按形态都可以划分以下这三类

  • redux流派
    redux、和基于redux衍生的其他作品,以及类似redux思路的作品,代表作有dva、rematch等等。
  • mobx流派
    借助definePerperty和Proxy完成数据劫持,从而达到响应式编程目的的代表,类mobx的作品也有不少,如dob等。
  • Context流派
    这里的Context指的是react自带的Context api,基于Context api打造的数据流方案通常主打轻量、易用、概览少,代表作品有unstated、constate等,大多数作品的核心代码可能不超过500行。

到此我们看看Recoil应该属于哪一类?很显然按其特征属于Context流派,那么我们上面说的主打轻量对 Recoil并不适用了,打开其源码库发现代码并不是几百行完事的,所以基于Context api做得好用且强大就未必轻量,由此看出facebookRecoil是有野心并给予厚望的。

我们同时也看看Concent属于哪一类呢?Concentv2版本之后,重构数据追踪机制,启用了defineProperty和Proxy特性,得以让react应用既保留了不可变的追求,又享受到了运行时依赖收集和ui精确更新的性能提升福利,既然启用了defineProperty和Proxy,那么看起来Concent应该属于mobx流派?

事实上Concent属于一种全新的流派,不依赖react的Context api,不破坏react组件本身的形态,保持追求不可变的哲学,仅在react自身的渲染调度机制之上建立一层逻辑层状态分发调度机制,defineProperty和Proxy只是用于辅助收集实例和衍生数据对模块数据的依赖,而修改数据入口还是setState(或基于setState封装的dispatch, invoke, sync),让Concent可以0入侵的接入react应用,真正的即插即用和无感知接入。

即插即用的核心原理是,Concent自建了一个平行于react运行时的全局上下文,精心维护这模块与实例之间的归属关系,同时接管了组件实例的更新入口setState,保留原始的setState为reactSetState,所有当用户调用setState时,concent除了调用reactSetState更新当前实例ui,同时智能判断提交的状态是否也还有别的实例关心其变化,然后一并拿出来依次执行这些实例的reactSetState,进而达到了状态全部同步的目的。

0d36b14fd2ae72f2f6a57fdd8d4bce8a.png

Recoil初体验

我们以常用的counter来举例,熟悉一下Recoil暴露的四个高频使用的api - atom,定义状态 - selector, 定义派生数据 - useRecoilState,消费状态 - useRecoilValue,消费派生数据

定义状态

外部使用atom接口,定义一个key为num,初始值为0的状态

const numState = atom({
    
  key: "num",
  default: 0
});

定义派生数据

外部使用selector接口,定义一个key为numx10,初始值是依赖numState再次计算而得到

const numx10Val = selector({
    
  key: "numx10",
  get: ({
     get }) => {
    
    const num = get(numState);
    return num * 10;
  }
});

定义异步的派生数据

selectorget支持定义异步函数

需要注意的点是,如果有依赖,必需先书写好依赖在开始执行异步逻辑
const delay = () => new Promise(r => setTimeout(r, 1000));

const asyncNumx10Val = selector({
    
  key: "asyncNumx10",
  get: async ({
     get }) => {
    
    // !!!这句话不能放在delay之下, selector需要同步的确定依赖
    const num = get(numState);
    await delay();
    return num * 10;
  }
});

消费状态

组件里使用useRecoilState接口,传入想要获去的状态(由atom创建而得)

const NumView = () => {
  const [num, setNum] = useRecoilState(numState);

  const add = ()=>setNum(num+1);

  return (
    <div>
      {num}<br/>
      <button onClick={add}>add</button>
    </div>
  );
}

消费派生数据

组件里使用useRecoilValue接口,传入想要获去的派生数据(由selector创建而得),同步派生数据和异步派生数据,皆可通过此接口获得

const NumValView = () => {
  const numx10 = useRecoilValue(numx10V
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值