面试官:你做的组件库里,Tree 组件的性能优化是怎么做的,能实现按需渲染吗?我:😭

512 阅读4分钟

在面试过程中提到组件封装,很多的面试官都喜欢让你手写一个组件,或者讲一讲他的思路。

笔者也是在两次面试过程中被问过,所以我开发这个企业级的 Tree 组件。

面试官为什么要这么问呢?

其实并不是想要你写代码,重要的是你怎么做架构设计的,你需要说出来你怎么设计的,不管设计好坏都可以。

地上组件库【Tree】

如果想了解代码实现细节的,可以去看我的 github

顺便帮我点一颗小星星可以吗?各位程序员里面的小帅哥小美女

github 仓库地址

🤖 这是我开发的企业级 Tree 组件

本文只讲架构思路,思路是唯一的,代码不重要

把自己当成产品经理,根据思路的指导可以随意开发代码

🤖 一个完备的 Tree 组件应该具备什么功能

  1. 受控属性
    1. 展开
    2. 点击
    3. 选择
  2. 可展开
    1. 懒加载
    2. 按需渲染
  3. 可点击
    1. 父子节点无关联
    2. indeterminate
    3. 按需渲染
  4. 可选择
    1. 按需渲染
  5. 可拖拽 dnd-kit
  6. 虚拟列表 react-window

功能这么多,是不是想打退堂鼓了,但是不要怕,这么多的功能

底层代码就 100 多行,剩下的其实就是在这个架构上面摞代码而已

🤖 分层架构 架构就是搭积木

1. 数据层

为什么需要数据层,而不直接 setState

  1. 简单组件直接 setState 都无所谓的
  2. 复杂组件最好抽离一个数据层,最后再根据这些数据决定哪些组件要重渲染 性能:直接操作对象 > setState > 直接操作 dom 节点
export function Tree(props) {
  const { data } = props;

  const treeNodeManager = useTreeNodeManager(data, props);

  return 'ui 层'
}

useTreeNodeManager 你在赣什么?

  1. new 了一个统一管理 Tree 组件的实例 treeNodeManager

treeNodeManagerTree 组件重渲染了我也不重新创建,服吗?

images.jpg

  1. treeNodeManager: Tree 组件内部所有的数据都是我的,你要对数据进行增删查改,得 V我20,才能调用我的方法,对数据进行修改

2. 中间层 连接数据层和 ui

出现企业级事故:数据层是抽离出来了,现在通过数据层修改数据,ui 层不重渲染,坏事了 😱

简单的批爆,一个观察者模式简简单单解决事故

function Row({index}) {
  const treeNode = useTreeNode(index);
  return treeNode.data.label
}

export function useTreeNode(index: number) {
  const treeNodeManager = useTreeNodeManagerContext();
  const treeNode = useSyncExternalStore(
    treeNodeManager.subscribe,
    () => treeNodeManager.getNodeByIndex(index),
    () => treeNodeManager.getNodeByIndex(index)
  );
  return treeNode;
}
  1. useSyncExternalStore 内部,react 通过 treeNodeManager.subscribe 订阅一个回调存到 treeNodeManager里面
  2. 有没有记住上面数据层 treeNodeManager 说了啥?所有的数据的增删查改都归他管
  3. 什么时候你想组件重渲染了,你修改完数据后面执行一句 所有 react 注册的回调函数数组.forEach(回调 => 回调()) 不就完了

react 注册的这些回调到底做了些啥?

  1. 只要执行回调,他就会重新调用 () => treeNodeManager.getNodeByIndex(index) 拿到最新值,跟上一次拿到的值做对比
  2. 如果变了,就会让用到这个 useSyncExternalStore 的函数组件重渲染 也就是按需渲染

详细的 useSyncExternalStore 盒中盒解析请快速阅读 面试官:你说你做过组件库,肯定了解过复杂组件状态管理的useSyncExternalStore吧?我:😭

3. ui

treeNodeManager:处理好的数据,对数据增删查改的方法都在我身上,想要都给你,还想怎样?

每个前端实现的 ui 层都不同。一千个前端有一千个哈莫雷特

download.jpg

简单的扣卡,ui 层无非就是把这些数据用漂亮的组件展示出来,把这些方法绑定到对应的标签上面嘛。

🤖 用到的设计模式

单例模式 treeNodeManager

适配器模式 中间层

观察者模式 useSyncExternalStore

🤖 用到的原则

单一原则 文件目录/模块/函数所有方面复杂度必须为一。我只有一颗脑细胞

里氏替换原则 看起来像鸭子,走起来像鸭子,他就是鸭子

依赖倒置原则 架构为主导不断重构,代码为垃圾随便瞎写。高大上方便邀功

开闭原则 千万不要修改别人甚至自己的代码,一定要加中间层处理。别人被 KTV 的时候方便甩锅

接口隔离原则 暂时不懂,985 高材生欧阳傲冰应该清楚。应该是 class 类里面的 private 函数

🤖 加餐:受控属性是怎么实现的?阅读量超过 5k 自动解锁

🤖 相关

面试官:听说你简历里写的精通 React 源码,那你给我讲讲 React Scheduler 呗?我:😡 工资加 2K

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

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

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

版权归许泽川所有

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