setState 是同步还是异步的
不同模式和调用场景下情况不同。
legacy 模式下在合成事件和生命周期钩子中表现为异步,在 setTimeout 和原生事件中表现为同步。
concurrent 模式都表现为异步。
异步。
- 每次改变 state 都会造成 render 的重渲染,将多次修改的 state 合并到一起可以提高效率和性能;
- render 阶段会比较慢,但是 commit 很快。如果 render 中有子组件,子组件的 props 依赖父组件的 state,props 和 state 就不能保持一致
如何获取异步时的 state?
- 在 setState 的回调函数(第二个参数)
- 在 componentDidUpdate 中
同步。
如何获取同步的 state?
- 原生 js 获取 DOM 元素并绑定事件(原生事件)
- 计时器 setTimeout 中
调用 setState 发生了什么?
- 进入 Reconciler(协调器)计算出状态变化
- 状态变化通过 effect 进入 Renderer(渲染器)并被渲染在视图中
生命周期相关内容?
挂载阶段
- 调用 ReactDOM.render
- 进入 render 阶段
- 深度优先遍历创建 Fiber 树
- 针对每个 Fiber 节点调用一次生命周期函数(constructor、GDSFP、render)
- 进入 commit 阶段,将 Fiber 渲染到视图中
- 从子节点开始执行对应生命周期函数(componentDidMount)
更新阶段
9. 深度优先遍历创建 Fiber 树
10. 当节点产生变化时,再调用生命周期函数(GDSFP、render)
11. 进入 commit 阶段,执行变化对应的视图操作及生命周期(GSBU)
12. 将 Fiber 渲染到视图(componentDidUpdate)
useEffect(fn, []) 和 componentDidMount 有什么区别
useEffect(fn, []) 在commit 阶段完成后异步调用
componentDidMount 在 layout 阶段完成后同步调用
useLayoutEffect(fn, []) 在 layout 阶段完成后同步调用