先记住这个答案
可以从设计稿中的业务区域和重复结构出发,结合数据形状划分组件职责,先用 props 组成静态界面,再识别用户能独立改变的最小状态。多个组件需要协调同一值时,把状态放到合适的共同所有者;能由现有输入推导的结果直接计算。拆分应改善理解、复用或变化隔离,不要求每个 DOM 节点独立成组件,也不应把所有状态提前放进全局 Context。
- 视觉区域提供线索,职责与数据流决定最终边界
- 先识别最小独立状态,再推导展示结果
- 状态靠近实际消费者,跨区域协调时再提升
从商品搜索页找出职责边界
一个商品页可以包含搜索条件、结果摘要和商品列表,列表再复用商品卡片。搜索区负责收集条件,列表负责展示传入的结果,卡片负责单项内容与局部动作。这些边界与职责相关,而不只是依据背景颜色、边框或设计工具中的图层名称。
也不必把每行文本、每个图标都单独抽成组件。若提取后只增加跳转文件的成本,没有独立规则、复用或测试价值,可以先保持在附近。相反,一个看似小按钮若承载权限、加载和确认流程,可能值得建立清楚边界,即使设计稿中面积很小。
先用静态数据走通结构,再加入最小状态
静态版本可以帮助确认组件需要哪些 props、空列表怎样显示和重复项如何标识。随后加入搜索词、选中分类等独立输入,再直接计算过滤结果与命中数量。若同时保存原列表、筛选列表和数量,就必须维护多份数据的一致性,删除商品时很容易漏更新其中一份。
异步数据也要区分来源:服务端商品集合来自数据层,用户正在编辑的搜索框属于交互状态,搜索得到的可见列表可能是客户端派生结果,也可能是服务端查询结果。不能因为界面看起来一样就假定它们拥有相同的缓存、错误和更新规则。
由协调需求找到状态所有者
搜索区改变条件,列表和摘要都要读取结果,可以在包住三者的页面组件中管理条件。卡片独有的展开状态若不需要互斥协调,则可以留在卡片内;如果业务要求一次只展开一张卡片,就应把当前展开 ID 放到能协调所有卡片的层级。
最后再检查跨层传递是否冗长,考虑组件组合或 Context。结构完成后应模拟筛选、删除、加载失败和快速切换,确认每种状态只有明确来源。性能优化也要围绕实际昂贵区域,不能先把所有组件加 memo,再用稳定 props 的困难反过来决定业务结构。
容易答错的地方
- 设计稿有一个框,就必须对应一个组件
- 图层是视觉组织方式,未必对应独立职责。组件边界还要看输入、行为、生命周期与变化原因,不能让设计工具的分组完全替代工程判断。
- 提取组件后必须同时提取一份 state
- 拆分展示不意味着复制状态。子组件可以只接收 props,独立 state 应由真实交互与生命周期需要决定,否则容易出现父子各保存同一值的同步问题。
面试官还会怎么问?
什么时候把复杂组件继续拆小?
当它同时处理多种独立变化、难以命名输入,或某部分需要单独复用和验证时,可以按职责提取。单看代码行数只能提供信号,不能给出稳定的拆分边界。
两个组件共享状态一定放在最近共同祖先吗?
这是常见起点,还要看状态需要保留多久以及业务所有者是谁。如果该祖先会在切换时卸载而状态必须保留,就要选择持续存在的所有者或保存恢复机制。
后端响应结构应该直接决定前端组件树吗?
数据结构能帮助识别重复项与关系,但接口可能为传输效率设计,组件则服务于交互与展示。可以在数据边界做适当转换,避免接口嵌套层级机械映射成组件嵌套。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。