标准答案
- 先区分展示组件、容器组件和业务组件,避免一个组件同时负责请求、权限、布局、弹窗和表单提交。
- 组件 props 应表达业务语义,而不是暴露内部 DOM、样式细节或页面级状态结构。
- 副作用和数据请求可以放在页面层、自定义 Hook 或数据层,组件通过数据和回调协作。
- 插槽式能力可以用 children、render props 或组合组件表达,不要靠大量布尔 props 堆分支。
- 组件要保留扩展点,例如空状态、操作区、权限控制和错误态,但不要为了所有未来场景过度抽象。
题目解析
这道题关注组件边界。低耦合不是没有业务含义,而是不要让组件直接依赖具体页面流程。
好的业务组件通常可以在相近场景复用,但不追求跨所有业务线通用。
判断封装是否合适,可以看它换接口、换页面、换权限来源时是否需要大改内部实现。
代码示例
下面的用户选择器只关心 value、options 和 onChange,不直接知道页面如何请求数据。
TSX
type UserSelectProps = {
value?: string
options: Array<{ id: string; name: string }>
disabled?: boolean
onChange: (userId: string) => void
}
function UserSelect({ value, options, disabled, onChange }: UserSelectProps) {
return (
<select value={value} disabled={disabled} onChange={event => onChange(event.target.value)}>
{options.map(user => (
<option key={user.id} value={user.id}>{user.name}</option>
))}
</select>
)
}常见误区
- 组件内部直接请求固定接口,导致同类业务页面很难复用。
- 为了通用性加入几十个布尔 props,组件分支比页面还复杂。
- 把权限、路由、埋点和弹窗流程都塞进一个展示组件里。