在面试过程中提到组件封装,很多的面试官都喜欢让你手写一个组件,或者讲一讲他的思路。
笔者也是在两次面试过程中被问过,所以我开发这个企业级的 Tree 组件。
面试官为什么要这么问呢?
其实并不是想要你写代码,重要的是你怎么做架构设计的,你需要说出来你怎么设计的,不管设计好坏都可以。
地上组件库【Tree】
如果想了解代码实现细节的,可以去看我的
github
顺便帮我点一颗小星星可以吗?各位程序员里面的小帅哥小美女
🤖 这是我开发的企业级 Tree
组件
本文只讲架构思路,思路是唯一的,代码不重要
把自己当成产品经理,根据思路的指导可以随意开发代码
🤖 一个完备的 Tree
组件应该具备什么功能
- 受控属性
- 展开
- 点击
- 选择
- 可展开
- 懒加载
- 按需渲染
- 可点击
- 父子节点无关联
indeterminate
- 按需渲染
- 可选择
- 按需渲染
- 可拖拽 dnd-kit
- 虚拟列表 react-window
功能这么多,是不是想打退堂鼓了,但是不要怕,这么多的功能
底层代码就
100
多行,剩下的其实就是在这个架构上面摞代码而已
🤖 分层架构 架构就是搭积木
1. 数据层
为什么需要数据层,而不直接
setState
?
- 简单组件直接
setState
都无所谓的- 复杂组件最好抽离一个数据层,最后再根据这些数据决定哪些组件要重渲染 性能:直接操作对象 >
setState
> 直接操作dom
节点
export function Tree(props) {
const { data } = props;
const treeNodeManager = useTreeNodeManager(data, props);
return 'ui 层'
}
useTreeNodeManager
你在赣什么?
new
了一个统一管理Tree
组件的实例treeNodeManager
treeNodeManager
: Tree
组件重渲染了我也不重新创建,服吗?
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;
}
useSyncExternalStore
内部,react
通过treeNodeManager.subscribe
订阅一个回调存到treeNodeManager
里面- 有没有记住上面数据层
treeNodeManager
说了啥?所有的数据的增删查改都归他管 - 什么时候你想组件重渲染了,你修改完数据后面执行一句
所有 react 注册的回调函数数组.forEach(回调 => 回调())
不就完了
react
注册的这些回调到底做了些啥?
- 只要执行回调,他就会重新调用
() => treeNodeManager.getNodeByIndex(index)
拿到最新值,跟上一次拿到的值做对比- 如果变了,就会让用到这个
useSyncExternalStore
的函数组件重渲染 也就是按需渲染详细的
useSyncExternalStore
盒中盒解析请快速阅读 面试官:你说你做过组件库,肯定了解过复杂组件状态管理的useSyncExternalStore吧?我:😭
3. ui
层
treeNodeManager
:处理好的数据,对数据增删查改的方法都在我身上,想要都给你,还想怎样?
每个前端实现的 ui
层都不同。一千个前端有一千个哈莫雷特
简单的扣卡,ui
层无非就是把这些数据用漂亮的组件展示出来,把这些方法绑定到对应的标签上面嘛。
🤖 用到的设计模式
单例模式 treeNodeManager
适配器模式 中间层
观察者模式 useSyncExternalStore
🤖 用到的原则
单一原则 文件目录/模块/函数所有方面复杂度必须为一。我只有一颗脑细胞
里氏替换原则 看起来像鸭子,走起来像鸭子,他就是鸭子
依赖倒置原则 架构为主导不断重构,代码为垃圾随便瞎写。高大上方便邀功
开闭原则 千万不要修改别人甚至自己的代码,一定要加中间层处理。别人被 KTV 的时候方便甩锅
接口隔离原则 暂时不懂,985
高材生欧阳傲冰应该清楚。应该是 class
类里面的 private
函数
🤖 加餐:受控属性是怎么实现的?阅读量超过 5k
自动解锁
🤖 相关
面试官:听说你简历里写的精通 React 源码,那你给我讲讲 React Scheduler 呗?我:😡 工资加 2K
面试官:你说你做过组件库,肯定了解过复杂组件状态管理的useSyncExternalStore吧?我:😭
版权归许泽川所有
如需转载,请提前询问本人的许可