用途
本技能用于处理前端代码中的耦合问题,核心目标是“最小化代码变更的影响范围”:一次功能改动不应破坏其他功能。当出现以下信号时适用:props 需要穿过 3 层以上组件层级;一个 Hook 返回 5 个以上值;修改 A 时导致无关的 B 出错。
主要能力
资料给出的核心模式与改进方法如下:
- 消除 Props Drilling(组合模式)
问题写法:props 逐层向下传递。
function ItemEditModal({ items, onConfirm, onClose }) {
return (
<Modal onClose={onClose}>
<ItemEditBody items={items} onConfirm={onConfirm} onClose={onClose} />
</Modal>
);
}
function ItemEditBody({ items, onConfirm, onClose }) {
return (
<>
<Button onClick={onClose}>닫기</Button>
<ItemEditList items={items} onConfirm={onConfirm} />
</>
);
}
改进写法:用 children 进行组合。
function ItemEditModal({ items, onConfirm, onClose }) {
return (
<Modal onClose={onClose}>
<ItemEditBody onClose={onClose}>
<ItemEditList items={items} onConfirm={onConfirm} />
</ItemEditBody>
</Modal>
);
}
function ItemEditBody({ children, onClose }) {
return <><Button onClick={onClose}>닫기</Button>{children}</>;
}
- 职责分离
问题写法:一个 Hook 管理所有状态。
function usePageState() {
const [query] = useQueryParams({
cardId: NumberParam, dateFrom: DateParam, dateTo: DateParam, statusList: ArrayParam
});
}
改进写法:拆分为单一职责 Hook。
function useCardIdQueryParam() {
const [cardId, setCardId] = useQueryParam("cardId", NumberParam);
return [cardId ?? undefined, setCardId] as const;
}
快速参考
资料提供的“代码坏味道 → 改进方法”对照:
- 穿过 3 层以上层级的 props → 组合模式:使用 children
- 返回 5 个以上值的 Hook → 拆分为单一职责 Hook
- 修改 A 时无关的 B 出错 → 识别耦合点后引入接口
- 被所有地方 import 的 util → 移动到使用处附近
适用场景
- 组件层级较深、props 层层透传的界面结构。
- Hook 承担过多职责、返回值过多的情况。
- 修改一处代码牵连多处、影响范围难以预估的代码库。
- 公共 util 被广泛引用、改动成本高的项目。
限制与注意事项
- Context 的适用条件:仅用于真正的全局关注点,例如主题、语言区域(locale)、认证状态,或需要被 10 个以上组件使用的数据。不要为了回避组合模式而滥用 Context。
- 例外:有些情况下重复反而更好——当各页面行为存在差异的可能时;当修改公共代码会导致所有依赖代码的测试负担过大时。
参考
https://frontend-fundamentals.com/code-quality/loosely-coupled/