3. 组件与Props深度剖析:函数组件vs类组件、Props类型校验、组件通信、复合组件模式
面试官常通过以下层面评估候选人的组件抽象能力:
- 函数组件 vs 类组件:生命周期、Hooks、性能权衡
- Props类型校验:PropTypes / TypeScript 静态检查
- 组件通信:props、回调、Context、状态提升
- 复合组件模式:render props、children、自定义Hook
问答1:函数组件 vs 类组件
面试问题:请比较 React 函数组件与类组件的核心区别,并说出你在项目中如何选择。
面试官考察点:
对 React 架构演进的理解、Hooks 原理、性能与可维护性权衡。
回答框架:
① 定义方式与状态管理差异;② 生命周期对应关系;③ Hooks 优势;④ 项目实际选择依据(团队经验、复杂度、性能敏感度)。
简短示例回答:
“类组件通过 this.state 和生命周期管理,函数组件用 Hooks 实现状态和副作用。我偏好函数组件,因为 Hooks 使逻辑复用更简洁,且避免 this 绑定问题。复杂错误边界或需要 componentDidCatch 时保留类组件。”
可能追问:
“如果函数组件需要用 shouldComponentUpdate 怎么办?”(答:用 React.memo + useMemo 模拟)
“Hooks 为什么不能在条件语句中使用?”(答:Hooks 调用顺序依赖链表结构)
避坑提醒:
不要只说“新项目都用函数组件”,要说明场景;注意类组件的 .bind 性能开销;演示时避免理解偏差:componentWillMount 已被废弃。
问答2:Props类型校验
面试问题:你如何保证组件 Props 的类型安全?PropTypes 与 TypeScript 如何选择?
面试官考察点:
工程化规范意识、两种方案优缺点、团队协作视角。
回答框架:
① PropTypes 运行时校验 vs TS 编译时校验;② 项目类型复杂度决定;③ 实际项目中如何结合使用。
简短示例回答:
“我优先使用 TypeScript 定义接口,编译阶段捕获类型错误;对第三方库或遗留代码会补充 PropTypes 运行时告警。TS 类型更严谨,配合 generic 能约束复杂嵌套结构。”
可能追问:
“如何对 children 进行类型校验?”(答:使用 React.ReactNode 或 React.FC 的隐式 children)
“PropTypes 的 oneOfType 实际使用场景?”(答:联合类型,如 error 字段可能是 string 或 { message: string })
避坑提醒:
不要认为 PropTypes 已过时;注意 TS 中 defaultProps 与类型推断的冲突(React 18+ 推荐设置默认值)。
问答3:组件通信
面试问题:请列出 React 组件间的通信方式,并说明不同场景下的选择依据。
面试官考察点:
组件设计分层能力、状态管理选型、过度设计判定。
回答框架:
① 父子通信(props / 回调);② 兄弟通信(状态提升到父组件);③ 跨层级通信(Context / Redux / Event Bus);④ 何时引入全局状态。
简短示例回答:
“父子用 props 传递数据和回调;兄弟通过父组件提升共享状态;跨层级用 Context 避免 prop drilling。只有复杂全局状态(如用户登录、购物车)才会引入 Redux。不推崇 Event Bus,维护性差。”
可能追问:
“Context 会导致全树重新渲染吗?”(答:值变化时所有 Consumer 都会重渲染,可通过 memo 或 useMemo 优化)
“如何实现非嵌套组件通信?”(答:使用发布订阅库或 Context 提供全局 store)
避坑提醒:
避免过度使用 Context 导致性能问题;兄弟通信不要直接通过 ref 操作对方组件。
项目案例:电商后台管理系统的组件重构
| 维度 | 内容 |
|---|---|
| 项目名称 | 电商后台管理页面组件库重构(内部代号Luna) |
| 业务背景 | 既有页面使用大量重复Props逻辑,代码耦合度高;需要统一组件规范,提升开发效率和可测试性。 |
| 规模指标 | 50+ 业务页面,200+ 基础组件,日均 1000+ 次组件调用。重构后减少40%的props传递层级。 |
| 技术栈 | React 18 + TypeScript + Redux Toolkit + React Hook Form + 内部UI库(基于Ant Design二次封装) |
| 核心难点 | 1) 复杂搜索表单中筛选条件跨三层组件传递;2) 复合组件模式(Table + Filter + Pagination)的状态同步;3) Props类型与defaultValues的联动。 |
| 面试高频追问 |
“如何避免上述场景的Props Drilling?”(答:使用组合 + Context 提供局部状态,或者自定义Hook封装逻辑) “复合组件模式下如何保证子组件独立可测?”(答:每个子组件暴露最小Props接口,复合组件负责聚合状态) “TypeScript 如何约束复杂嵌套Props?”(答:利用 Pick / Omit / Partial 派生类型)
|
| 可迁移回答话术 |
“我在项目中采用复合组件模式,把相关子组件通过 children 或 render props 组合,父组件只传递共享状态,子组件通过 Hook 或 Context 获取所需数据,减少了Props逐层传递,同时每个子组件可以独立测试。”
|