PLC程序解锁解码的详细介绍

今日头条

1096人已加入

描述

PLC程序解锁解码【电;I7I54833762】方法和思路分享,首先是设置 subscription 的 onStateChange(它初始是个空方法,需要注入实现),它会在触发更新时调用,它这里希望将来调用的是subscription.notifyNestedSubssubscription.notifyNestedSubs会触发这个 subscription 收集的所有子订阅。也就是说这里的更新回调和『更新』没有直接关系,而是触发子节点们的更新方法。

然后调用了subscription.trySubscribe(),它会将自己的 onStateChange 交给父级 subscription 或者 redux 去订阅,将来由它们触发 onStateChange

最后它会判断之前的 state 和最新的是否一致,如果不一致会调用subscription.notifyNestedSubs(),它会触发这个 subscription 收集的所有子订阅从而更新它们。

返回了注销相关的函数,它会注销在父级的订阅,将subscription.onStateChange重新置为空方法。这个函数会在组件卸载或 re-render (仅 store 变化时)时被调用(react useEffect 的特性)。

Provider 有很多地方都涉及到了 subscription,subscription 的那些方法只是讲了大概功能,关于 subscription 的细节会在后面 subscription 的部分讲到。

这里会讲到 Provider 中出镜率很高的 subscription 部分,它是 react-redux 能够嵌套收集订阅的关键。其实这个部分的标题叫做 Subscription 已经不太合适了,在 8.0.0 版本之前,react-redux 确实是通过 Subscription class 实现它的,你可以通过new Subscription()使用创建 subscription 实例。但在 8.0.0 之后,已经变成了createSubscription函数创建 subscription 对象,内部用闭包替代原先的属性。

用函数替代 class 有一个好处是,不需要关心 this 的指向,函数返回的方法修改的永远是内部的闭包,不会出现 class 方法被赋值给其他变量后出现 this 指向变化的问题,降低了开发时的心智负担。闭包也更加私有化,增加了变量安全。同时在一个支持 hooks 的库里,用函数实现也更符合开发范式。

addNestedSub非常巧妙的运用了递归,它里面又调用了trySubscribe。于是它们就会达到这样的目的,当最底层subscription发起trySubscribe想被父级收集订阅时,它会首先触发父级的trySubscribe并继续递归直到根subscription,如果我们把这样的层级结构想象成树的话(其实 subscription.trySubscribe 也确实发生在组件树中),那么就相当于从根节点到叶子节点依次会被父级收集订阅。因为这是由叶子节点先发起的,这时除了叶子节点,其他节点的订阅回调还没有被设置,所以才设计了handleChangeWrapper这个回调外壳,注册的只是这个回调外壳,在将来非叶子节点设置好回调后,能被外壳触发。

在『递』过程结束后,从根节点开始到这个叶子节点的订阅回调handleChangeWrapper都正在被父级收集了,『归』的过程回溯做它的本职工作return listeners.subscribe(listener),将子subscription的订阅回调收集到收集器listeners中(将来更新发生时会触发相关的handleChangeWrapper,而它会间接的调用收集到所有的 listener)。

所以每个subscriptionaddNestedSub都做了两件事:1. 让自己的订阅回调先被父级收集;2. 收集子subscription的订阅回调。

结合addNestedSub的解释再回过头来看trySubscribe,它想让自己的订阅回调被父级收集,于是当它被传入父级subscription时,就会调用它的addNestedSub,这会导致从根subscription开始每一层subscription都被父级收集了回调,于是每个subscription都嵌套收集了它们子subscription,从而父级更新后子级才更新成为了可能。同时,因为unsubscribe这个锁的存在,如果某个父级subscriptiontrySubscribe被调用了,并不会重复的触发这个『嵌套注册』。

useIsomorphicLayoutEffectWithArgs是一个工具函数,内部是useIsomorphicLayoutEffect,这个函数前面也讲过。它们最终做的是:将第 2 个数组参数的每项作为参数给第一个参数调用,第 3 个参数是useIsomorphicLayoutEffect的缓存依赖。

被执行的第一个参数captureWrapperProps,它主要功能是判断如果是来自 store 的更新,则在更新完成后(比如 useEffect)触发subscription.notifyNestedSubs,通知子订阅更新。

接着它想生成actualChildProps,也就是 select 出来的业务组件需要的 props,其中主要使用了useSyncExternalStore,如果你追到useSyncExternalStore的代码里看,会发现它是一个空方法,直接调用会抛出错误,所以它是由外部注入的。在入口index.ts里,initializeConnect(useSyncExternalStore)对它进行初始化了,useSyncExternalStore来自 React 。所以actualChildProps实际是React.useSyncExternalStore( subscribeForReact, actualChildPropsSelector, getServerState ? () => childPropsSelector(getServerState(), wrapperProps) : actualChildPropsSelector)的结果。

useSyncExternalStore是 react18 的新 API,前身是useMutableSource,为了防止在 concurrent 模式下,任务中断后第三方 store 被修改,恢复任务时出现tearing从而数据不一致。外部 store 的更新可以通过它引起组件的更新。在react-redux8之前,是由useReducer手动实现的,这是react-redux8首次使用新 API。这也意味着你必须跟着使用 React18+。但我认为其实 react-redux8 可以用 shim: import { useSyncExternalStore } from 'use-syncexternal-store/shim';来做到向下兼容。

审核编辑:符乾江

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分