面试官:你跟我说 setState 是同步的,它不是异步的吗?背错面试题了吧你!我:😭

3,227 阅读5分钟

setState 同步还是异步的,很多前端都回答是异步的,这样面试官觉得没有新意。怎么回答会让面试官眼前一亮呢?

🤖 我为什么说 setState 为什么是同步的呢?

因为 setState 他确实是一个同步函数啊。他嗖的一下就执行完了,只不过他安排了一个异步任务

这也是许多前端新人前期学 react 常常踩的一个坑,只不过还有前端新人吗?😭

接下来我将给你们进行一波 react 源码级别的企业级讲解

🤖 setState 你在赣什么?

function App() {
  const [state, setState] = useState('三和大神')
  function handleClick() {
    setState('许泽川')
    console.log(state)
  }
  return <div onClick={handleClick}>{state}</div>
}
  1. 在不同的地方调用 setState,会创建不同优先级的更新。比如这里在点击事件里面触发,会创建一个优先级为 1许泽川 的更新
  2. 根据更新的优先级,通过宏任务或者微任务注册一个任务。 这个任务就是:触发重渲染,通过这个新的 许泽川 更新创建出新的 App Fiber

有的急性子, setState 完就想拿来用,发现,咋还是三和大神。

setState: 我值都还没改,服吗?😈

🤖 小贴士

🚀 优先级

抄袭浏览器的事件优先级

  1. React 一共有 4 种优先级,从高到低是离散事件点击、连续事件输入、滚动、默认事件、空闲事件

  2. 32位二进制切成四个部分,给四种优先级分,离散事件1车道、连续事件01车道001车道、默认事件0001车道、空闲事件剩下的车道都归我

  3. 每次 setState 会判断当前上下文拿一个车道出来,创建一个车道对应优先级的更新,和对应优先级的重渲染任务来处理这个更新

  4. 离散事件优先级最高,通过微任务queueMicrotask执行重渲染。连续事件默认事件空闲事件全部通过宏任务 MessageChannel执行重渲染

todo 空闲事件时间切片

🚀 批量渲染

在同一个地方 setState 多次,说明他有相同的优先级

源码有一个条件语句,只要发现是相同的优先级,函数就 return也就是只有第一次的 setState 安排了一个重渲染任务,之后的 setState 都跳过了

function 重渲染() {
    if (新的优先级 === 当前的优先级) return;

    根据当前 setState 的优先级,通过宏任务或者微任务注册一个重渲染任务
}

计算顺序不会出错

就是说啊,我们上面不是提了优先级嘛。那其实高优先级的 setState 能打断低优先级的 这个说来话长一时半会讲不清楚

比如现在 const [state, setState] = useState('许泽川')

然后我们在低优先级的上下文中,setState(state => state + '不是')

还没重渲染的时候,我们又在高优先级的上下文中,setState(state => state + '帅哥')

  1. 那么他会打断低优先级的,先处理高优先级的 setState,变成 许泽川帅哥

  2. 然后再处理低优先级的 setState,变成 许泽川帅哥不是

  3. 错了,是变成许泽川不是帅哥😠why,u tripping?

setState 执行了两次创建了 2 个不同优先级的 update

  1. 本来好好的,低优先级的 setState 执行,这时候的更新链条就只有他本身,也就是,内容就是在 许泽川后面加 不是
  2. 这时候高优先级的来了,低优先级被打断,这时候的更新链条就变成了低优先级的 update:state => state + '不是' ------> 高优先级的 update:state => state + '帅哥',然后应用更新,但是他只会更新当前优先级和优先级比他高的 update ,所以低优先级的 update 没有更新,所以变成了 许泽川帅哥
  3. 所以说低优先级的 update 是没有更新的,他被跳过了,但是会把跳过本身和他之后的链表保存起来,还会把这条链表更新前的值保存起来。也就是保存了 更新链表: 跳过的低优先级的 update:state => state + '不是' -> 高优先级的 update:state => state + '帅哥' 更新前的值:许泽川
  4. 高优先级的更新后,重渲染完成之后呢。react又会判断还有没有优先级,如果有又会重新触发一次重渲染。发现确实有一个低优先级的车道在等着。那这次就进行低优先级的重渲染,同样他会更新当前优先级和优先级比他高的 update,所以低优先级和高优先级的更新这一次都应用到了 更新前的值:许泽川 上,所以变成了 许泽川+不是+帅哥

小优化:eagerState

先赊个账,文章先发了,这个找到工作再补充

🤖 相关

面试官:你说你做过组件库,肯定了解过复杂组件状态管理的useSyncExternalStore吧?我:😭

面试官:你跟我说 setState 是同步的,它不是异步的吗?背错面试题了吧你!我:😭

面试官:你说你开发过组件库,那你怎么会不知道受控组件?面试就到这里吧。我:😭

版权归许泽川所有

如需转载,请提前询问本人的许可