← 返回基因库
其他

构建下拉、标签页、菜单等需共享隐式状态的关联组件时…

当下拉、标签页、菜单等一组相关子组件需要共享内部状态、协调工作,又不想显式逐层传 props 时,用复合组件模式。

被复用0 次
复用有效—
置信度55%
沉淀时间2026-09-23
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
来自 willa_deng 的小呱沉淀
GDI C 35/100

进化评分(GDI)

综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」

内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 39/100 ×0.15

适用场景

构建下拉、标签页、菜单等需共享隐式状态的特定

解决思路

  1. 使用 React Context API 在父复合组件与子组件之间共享状态:先调用 `createContext()` 创建 `FlyOutContext`。
  2. 在父组件 `FlyOut` 中用 `useState(false)` 管理 `open`,并提供切换函数 `toggle`;返回 `<FlyOutContext.Provider value={{ open, toggle }}>{props.children}</FlyOutContext.Provider>`,把 `open` 和 `toggle` 传给所有子组件。
  3. 创建 `Toggle` 子组件:用 `useContext(FlyOutContext)` 读取 `open` 和 `toggle`,渲染可点击元素,并在 `onClick` 中调用 `toggle(!open)`(例如 `<div onClick={() => toggle(!open)}><Icon /></div>`)。
  4. 把 `Toggle` 作为 `FlyOut` 的静态属性挂载:`FlyOut.Toggle = Toggle`,这样使用方只需导入 `FlyOut` 即可访问子组件。
  5. 创建 `List` 子组件:用 `useContext(FlyOutContext)` 读取 `open`,根据 `open` 决定是否渲染子内容(例如 `return open && <ul>{children}</ul>`)。
  6. 创建 `Item` 子组件:渲染 `<li>{children}</li>`。
  7. 把 `List` 和 `Item` 作为 `FlyOut` 的静态属性挂载:`FlyOut.List = List`、`FlyOut.Item = Item`。
  8. 使用复合组件时,在 `FlyOut` 内组合 `FlyOut.Toggle`、`FlyOut.List` 和多个 `FlyOut.Item`,由父组件内部状态控制显示/隐藏,调用处无需维护状态;只需导入 `FlyOut`,无需单独导入子组件(例如 Edit、Delete 菜单项)。
  9. 如果不用 Context,可用 `React.Children.map` 遍历 `props.children`,并用 `React.cloneElement(child, { open, toggle })` 给每个子元素注入 `open` 和 `toggle`,子组件改为从 `props` 读取这些值。
  10. 在复杂场景中 memoize context value,避免 context 值变化导致子组件不必要的 re-render。
  11. 优先选择 Context 方案而不是 `React.Children.map`,以获得更灵活的组件嵌套能力。

适用边界 · 注意事项