Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

精读《Immer.js》源码 #68

Closed
ascoders opened this issue Mar 13, 2018 · 6 comments
Closed

精读《Immer.js》源码 #68

ascoders opened this issue Mar 13, 2018 · 6 comments

Comments

@ascoders
Copy link
Owner

本周精读的源码是:https://github.com/mweststrate/immer

Immer 出来这么久了,为啥选它?因为最近它越来越火了。。我们当然不想知其然而不知所以然,所以,源码读起来吧~

@ascoders ascoders mentioned this issue Mar 19, 2018
65 tasks
@AsceticBoy
Copy link

你好,我觉得 Immer 中我比较不理解 getter 中为啥有些是需要 (state.copy[prop] = createProxy(state, value)) 而有些需要 (state.proxies[prop] = createProxy(state, value))。可是它最终在 setter 中都是 Object.assign(state.copy, state.proxies) 了,所以他这样做的意义或者优势在哪里

@AsceticBoy
Copy link

是不是因为 proxies 这玩样因为存了属性中已经访问过的代理对象,等再一次访问到同样属性的时候,取的快一点? @ascoders 希望大佬能帮忙解解惑

@ascoders
Copy link
Owner Author

首先记住,所有对象初始值存在 base 属性里,所有修改都不会碰 base,这是 immutable 的最基本原则,改的话放在 copy 里。

基本上说到这就很清楚了,base 存上个状态,copy 存下个状态,proxies 存中间状态(代理对象)。

下面的场景:

produce(draft => console.log(draft.a.b))

produce(draft => {
  draft.a = { b: 1 }
  draft.a.b = 2
  console.log(draft)
})

第一行是直接 getter,全程没有修改过对象,那直接给你代理对象扔到 proxies 里即可,这是最正常的做法。

后面是先修改了 draft.a,再通过 draft.a.b 访问到了 .a 属性,此时 draft 已经被修改过,直接访问 copy,将访问到的属性 proxy 化。至于说此时为什么不访问 proxies 而是 copy? 因为 copy 优先级比 proxies 高,已经修改过了,也就是有了 copyproxies 就不需要了。

所以 markChanged 有这么一段代码:

Object.assign(state.copy, state.proxies)

在任何对象触发 setter 后,把 proxies 赋给 copy(这些 proxies 是 getter 之前生成的),之后就再也不用 proxies 了。

@AsceticBoy
Copy link

AsceticBoy commented Mar 23, 2018

大佬,我想明白了,是我一开始对 proxy 理解的不够到位,draft.a.b = 2 如果没有事先给到 draft.a 的代理对象,draft.a.bsetter 都进不去。更不用说后面的操作了。所以必须要访问的中间态 proxies

@negativeentropy9
Copy link

那 immer.js 的作用只是在改变状态上为重组状态提供了方便呗(不用扩展原状态和生成新引用),存储方式并没有改变,仍然是浅拷贝。

@ponkans
Copy link

ponkans commented May 18, 2023

看作者第一版代码就都比较明确了 https://github.com/immerjs/immer/tree/1b8a694eda1cbbf68196fb74c6d56bc53449924a

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants