搜集了部分React作者 Dan Abramov 对于React的看法。
就像网友对尤大说的:《他根本不懂Vue》
React
React元素
React 元素并不是永远存在的 。它们总是在重建和删除之间不断循环着。
React 元素具有不可变性。例如,你不能改变 React 元素中的子元素或者属性。如果你想要在稍后渲染一些不同的东西,你需要从头创建新的 React 元素树来描述它。
因此React 需要决定何时更新一个已有的宿主实例来匹配新的 React 元素,何时该重新创建新的宿主实例。
JSX
JSX是一个 JavaScript 的语法扩展,有人称它为Javascript XML,它的最大优点就是灵活,因为其本质就是JS,JS灵活所以JSX也灵活。
在React中,JSX会被编译成就是React.createElement()
JSX与模板都是视图层的DSL,二者各有千秋,个人看来模板有约束,但是约束之中会有性能提升的空间,(Vue的模板complier可以针对点对点进行diff),而JSX很灵活,但是却很难做到这一点。
JSX与模板的讨论
关于Vue3.0的模板为什么性能完爆JSX
更新流程
什么是更新,其实就是使宿主UI与React最新的元素树保持一致,将 React 元素树映射到宿主树(DOM/PDF/IOS)。
当父组件通过 setState 准备更新时,React 默认会协调整个子树。因为 React 并不知道在父组件中的更新是否会影响到其子代,所以 React 默认保持一致性。
React会生成一颗新的元素树,并在新旧两棵树之间做协调(Diff)。
批量更新:更新时,React 会先触发所有的事件处理器,然后再触发一次重渲染以进行所谓的批量更新,这就是在事件中setState是异步的原因。
React Fiber
React Fiber 是什么?
这可能是最通俗的 React Fiber(时间分片) 打开方式
漫画解释React Fiber
Fiber与Hooks是如何结合的
Javascript 引擎是单线程运行的。 严格来说,Javascript 引擎和页面渲染引擎在同一个渲染线程,GUI 渲染和 Javascript执行 两者是互斥的。另外异步 I/O 操作底层实际上可能是多线程的在驱动。
在React16之前,React协调是同步的(Stack Reconcilation),一边Diff一般更新dom,如果大批量同步更新会长期占用浏览器进程,是用户感觉到卡顿。而引用React Fiber之后,协调任务变成了异步,或者说,变成了一个协程(Fiber Reconcilation)。
Fiber解决的不是性能问题,而是调度问题。
① 将VirtualDOM 的数据结构改成了链表,这样可以避免递归而改成遍历,模拟函数调用栈
② 将渲染分为两个阶段,Reconciliation协调阶段和提交阶段,其中对生命周期函数的影响较大,废弃了部分生命周期。而提交阶段(前)的生命周期只能调用一次,所以大部分副作用会留在提交阶段调用。
协调阶段可能被中断、恢复,甚至重做,⚠️React 协调阶段的生命周期钩子可能会被调用多次!, 例如 componentWillMount 可能会被调用两次。
③双缓冲:React会维护一颗WorkInProgressTree,WIP树就是一个缓冲,它在Reconciliation 完毕后一次性提交给浏览器进行渲染。它可以减少内存分配和垃圾回收,WIP 的节点不完全是新的,比如某颗子树不需要变动,React会克隆复用旧树中的子树
④副作用的收集和提交
Hooks
React Hook 最佳实践 – React Blog
重渲染问题:React Hooks(四): immutable
useState
- useState的原理:为什么useState能把组件和state联系起来
- 函数式更新,意味着以函数的模式表达一个行为,让state来更新:setCount(c => c + 1)
- hooks 的 setState: 如果前后两次的 state 引用相等,并不会刷新组件,因此需要用户进行保证当深比较结果不等的情况下,浅比较结果也不等,否则会造成视图和UI的不一致。
useEffect
- 函数式组件用了闭包,所以组件内部的任何函数,包括事件处理函数和 effect,都是从它被创建的那次渲染中被「看到」的。(class组件和函数式组件有何不同)
- useEffect 可以看成是渲染的一部分,或者是React数据流的一部分。因为每一次渲染都会有一个新的useEffect函数。
- 使用useReducer或者useRef获取state中的最新值以提供useEffect使用。
- 如果某些函数仅在effect中调用,你可以把它们的定义移到effect中。若该函数用到state(数据流),需要添加这个state到effect依赖项。再如果该函数还需要复用,最好放外面且用useCallback来包裹一层,再添加到依赖项。
- How to fetch data with React Hooks:你应该如何在React中请求数据。
useCallback
1.真正做到让函数参与到数据流,以props的形式传到子组件中,形成数据流,当callback中的函数变化时,props也会变化,这一点传统的class组件无法做到。
useRef
- 生成一个在组件生命周期共享的盒子,可以在盒子中存放dom或者其他属性(state)
- 而且对ref.current修改也不会引起组件渲染
- 更新 useRef 是 side effect (副作用),所以一般写在 useEffect 或 event handler 里
useRef详细总结
- to be continued