Token导航 LogoToken导航TokenDH.com
效率需要联网clawhub未标认证来源可访问clear审计通过

composition-patterns构图模式

Agent Skill

composition-patterns 用于辅助前端页面、组件、样式和交互逻辑开发,适合在 OpenClaw 中需要维护前端项目、生成组件或检查界面实现时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

25,476

周安装

1,051

GitHub Stars

公开资料未说明

下载量

8,324
OpenClaw

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

MIT-0

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:composition-patterns(构图模式)
来源仓库:https://github.com/wpank/composition-patterns
安装命令:
openclaw skills install composition-patterns
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 OpenClaw 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

ClawHubOpenClaw
openclaw skills install composition-patterns

简介

使用复合组件、上下文提供程序和显式变体构建灵活的 React 组件,以避免布尔属性扩散并提高可扩展性。

SKILL.md

name
react-composition-patterns
model
standard

React Composition Patterns

Build flexible, maintainable React components using compound components, context providers, and explicit variants. Avoid boolean prop proliferation.

WHAT

Composition patterns that scale:

  • Compound components with shared context
  • State/actions/meta context interface for dependency injection
  • Explicit variant components over boolean props
  • Lifted state in provider components
  • Children composition over render props

WHEN

  • Refactoring components with many boolean props
  • Building reusable component libraries
  • Designing flexible component APIs
  • Creating compound components (Card, Dialog, Form, etc.)
  • Components need shared state across sibling elements

KEYWORDS

composition, compound components, context, provider, boolean props, variants, react patterns, component architecture, render props, children

Source: Vercel Engineering

Installation

OpenClaw / Moltbot / Clawbot

npx clawhub@latest install composition-patterns

Core Principle

Avoid boolean prop proliferation. Each boolean doubles possible states.

// BAD: 4 booleans = 16 possible states
<Composer isThread isDMThread isEditing isForwarding />

// GOOD: Explicit variants, clear intent
<ThreadComposer channelId="abc" />
<EditComposer messageId="xyz" />

Pattern 1: Compound Components

Structure complex components with shared context. Consumers compose what they need.

const ComposerContext = createContext<ComposerContextValue | null>(null)

// Provider handles state
function ComposerProvider({ children, state, actions, meta }: ProviderProps) {
  return (
    <ComposerContext value={{ state, actions, meta }}>
      {children}
    </ComposerContext>
  )
}

// Subcomponents access context
function ComposerInput() {
  const { state, actions: { update }, meta: { inputRef } } = use(ComposerContext)
  return (
    <TextInput
      ref={inputRef}
      value={state.input}
      onChangeText={(text) => update(s => ({ ...s, input: text }))}
    />
  )
}

function ComposerSubmit() {
  const { actions: { submit } } = use(ComposerContext)
  return <Button onPress={submit}>Send</Button>
}

// Export as namespace
const Composer = {
  Provider: ComposerProvider,
  Frame: ComposerFrame,
  Input: ComposerInput,
  Submit: ComposerSubmit,
  Header: ComposerHeader,
  Footer: ComposerFooter,
}

Usage:

<Composer.Provider state={state} actions={actions} meta={meta}>
  <Composer.Frame>
    <Composer.Header />
    <Composer.Input />
    <Composer.Footer>
      <Composer.Formatting />
      <Composer.Submit />
    </Composer.Footer>
  </Composer.Frame>
</Composer.Provider>

Pattern 2: Generic Context Interface

Define a contract any provider can implement: state, actions, meta.

interface ComposerState {
  input: string
  attachments: Attachment[]
  isSubmitting: boolean
}

interface ComposerActions {
  update: (updater: (state: ComposerState) => ComposerState) => void
  submit: () => void
}

interface ComposerMeta {
  inputRef: React.RefObject<TextInput>
}

interface ComposerContextValue {
  state: ComposerState
  actions: ComposerActions
  meta: ComposerMeta
}

Same UI, different providers:

// Local state provider
function ForwardMessageProvider({ children }) {
  const [state, setState] = useState(initialState)
  return (
    <ComposerContext value={{
      state,
      actions: { update: setState, submit: useForwardMessage() },
      meta: { inputRef: useRef(null) },
    }}>
      {children}
    </ComposerContext>
  )
}

// Global synced state provider  
function ChannelProvider({ channelId, children }) {
  const { state, update, submit } = useGlobalChannel(channelId)
  return (
    <ComposerContext value={{
      state,
      actions: { update, submit },
      meta: { inputRef: useRef(null) },
    }}>
      {children}
    </ComposerContext>
  )
}

Both work with the same <Composer.Input /> component.


Pattern 3: Explicit Variants

Create named components for each use case instead of boolean modes.

// BAD: What does this render?
<Composer
  isThread
  isEditing={false}
  channelId="abc"
  showAttachments
/>

// GOOD: Self-documenting
<ThreadComposer channelId="abc" />

Implementation:

function ThreadComposer({ channelId }: { channelId: string }) {
  return (
    <ThreadProvider channelId={channelId}>
      <Composer.Frame>
        <Composer.Input />
        <AlsoSendToChannelField channelId={channelId} />
        <Composer.Footer>
          <Composer.Formatting />
          <Composer.Submit />
        </Composer.Footer>
      </Composer.Frame>
    </ThreadProvider>
  )
}

function EditComposer({ messageId }: { messageId: string }) {
  return (
    <EditProvider messageId={messageId}>
      <Composer.Frame>
        <Composer.Input />
        <Composer.Footer>
          <Composer.CancelEdit />
          <Composer.SaveEdit />
        </Composer.Footer>
      </Composer.Frame>
    </EditProvider>
  )
}

Pattern 4: Lifted State

Components outside the visual hierarchy can access state via provider.

function ForwardMessageDialog() {
  return (
    <ForwardMessageProvider>
      <Dialog>
        {/* Composer UI */}
        <Composer.Frame>
          <Composer.Input placeholder="Add a message" />
          <Composer.Footer>
            <Composer.Formatting />
          </Composer.Footer>
        </Composer.Frame>

        {/* Preview OUTSIDE composer but reads its state */}
        <MessagePreview />

        {/* Actions OUTSIDE composer but can submit */}
        <DialogActions>
          <CancelButton />
          <ForwardButton />
        </DialogActions>
      </Dialog>
    </ForwardMessageProvider>
  )
}

// Can access context despite being outside Composer.Frame
function ForwardButton() {
  const { actions: { submit } } = use(ComposerContext)
  return <Button onPress={submit}>Forward</Button>
}

function MessagePreview() {
  const { state } = use(ComposerContext)
  return <Preview message={state.input} attachments={state.attachments} />
}

Key insight: Provider boundary matters, not visual nesting.


Pattern 5: Children Over Render Props

Use children for composition, render props only when passing data.

// BAD: Render props for structure
<Composer
  renderHeader={() => <CustomHeader />}
  renderFooter={() => <Formatting />}
  renderActions={() => <Submit />}
/>

// GOOD: Children for structure
<Composer.Frame>
  <CustomHeader />
  <Composer.Input />
  <Composer.Footer>
    <Formatting />
    <Submit />
  </Composer.Footer>
</Composer.Frame>

When render props ARE appropriate:

// Passing data to children
<List
  data={items}
  renderItem={({ item, index }) => <Item item={item} index={index} />}
/>

Pattern 6: Decouple State from UI

Only the provider knows how state is managed. UI consumes the interface.

// BAD: UI coupled to state implementation
function ChannelComposer({ channelId }) {
  const state = useGlobalChannelState(channelId)  // Knows about global state
  const { submit } = useChannelSync(channelId)    // Knows about sync
  
  return <Composer.Input value={state.input} onChange={...} />
}

// GOOD: State isolated in provider
function ChannelProvider({ channelId, children }) {
  const { state, update, submit } = useGlobalChannel(channelId)
  
  return (
    <Composer.Provider
      state={state}
      actions={{ update, submit }}
      meta={{ inputRef: useRef(null) }}
    >
      {children}
    </Composer.Provider>
  )
}

// UI only knows the interface
function ChannelComposer() {
  return (
    <Composer.Frame>
      <Composer.Input />  {/* Works with any provider */}
      <Composer.Submit />
    </Composer.Frame>
  )
}

Quick Reference

Anti-PatternSolution
Boolean propsExplicit variant components
Render props for structureChildren composition
State in componentLift to provider
Coupled to state implGeneric context interface
Many conditional rendersCompose pieces explicitly

Files

  • rules/architecture-avoid-boolean-props.md - Detailed boolean prop guidance
  • rules/architecture-compound-components.md - Compound component pattern
  • rules/state-context-interface.md - Context interface design
  • rules/state-decouple-implementation.md - State isolation
  • rules/state-lift-state.md - Provider pattern
  • rules/patterns-explicit-variants.md - Variant components
  • rules/patterns-children-over-render-props.md - Composition over callbacks

NEVER

  • Add boolean props to customize behavior (use composition)
  • Create components with more than 2-3 boolean mode props
  • Couple UI components to specific state implementations
  • Use render props when children would work
  • Trap state inside components when siblings need access

适合场景

01

React 组件重构

02

组件库 API 设计

03

减少布尔参数

04

复合组件模式

能力概览

能力 1

提供组件组合规则

能力 2

减少布尔参数和复杂分支

能力 3

指导 compound components 和 context 模式

能力 4

适合组件库演进

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

OpenClaw

82.25%
按下载量换算6,846

安全审计

VirusTotal

通过

ClawScan

通过

Static analysis

未展示

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills