immer实现原理

357 阅读1分钟

代理对象

当produce接受到数据时会为原始数据创建一个代理对象作为draft对象传给你的回调函数。 之后当你读取draft的任意原始值时,你将会获取到一个被Proxy包装过的代理对象。(原因见下文) 例: 如下图中标有 红色点 的数据是被修改过的数据,有蓝色边框的数据是被监听的数据

为什么每次获取子属性时都需要返回一个新的Proxy对象?

Proxy只能监听一层属性的变化,无法获取到深层的改变。如 draft.a.b 的改变draft对象的Proxy handler是无法获取到的。 所以要监听深层属性变化需要在访问每层个非Proxy对象时都做一次代理操作。

修改属性

现在,一旦您尝试(直接或通过任何API)更改 Draft 对象上的某些内容,它将立即在与其相关的源对象树中创建该节点的克隆副本,并设置一个标记“已修改”。 从现在开始,以后对该副本对象的任何读写操作都不会体现在源树中,而会最终在副本树中。 此外,到目前为该副本节点的所有父节点都会标记为“已修改”。

当produce最终结束时,它将仅遍历代理树,如果修改了代理,则将其复制。 或者,如果不进行修改,则仅返回原始节点。 下图是对Proxy作用的图示说明。 Proxy的读写代理概述图