# React - Composition Patterns (Vercel Engineering)

Padroes de composicao para componentes React escalaveis. Fonte: Vercel composition-patterns.

## Regra #1: Evitar Boolean Props (CRITICAL)

```tsx
// NAO: Booleans duplicam estados possiveis
<Composer isThread isEditing={false} showAttachments showFormatting={false} />

// SIM: Variantes explicitas
<ThreadComposer channelId="abc" />
<EditMessageComposer messageId="xyz" />
<ForwardMessageComposer messageId="123" />
```

Cada boolean duplica os estados possiveis. 5 booleans = 32 combinacoes, maioria impossivel.

---

## Regra #2: Compound Components com Context (HIGH)

```tsx
// Compound Components: context partilhado, composicao explicita
const ComposerContext = createContext<ComposerContextValue | null>(null)

function ComposerFrame({ children }: { children: React.ReactNode }) {
  return <form>{children}</form>
}

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

// Exportar como compound
const Composer = {
  Frame: ComposerFrame,
  Input: ComposerInput,
  Submit: ComposerSubmit,
  Footer: ComposerFooter,
}

// Uso: composicao clara
<Composer.Frame>
  <Composer.Input />
  <Composer.Footer>
    <Composer.Submit />
  </Composer.Footer>
</Composer.Frame>
```

---

## Regra #3: State em Providers (HIGH)

```tsx
// NAO: Estado preso dentro do componente
function ForwardComposer() {
  const [state, setState] = useState(initialState)
  return <Composer.Frame>...</Composer.Frame>
}

// SIM: State lifted para Provider
function ForwardProvider({ children }: { children: React.ReactNode }) {
  const [state, setState] = useState(initialState)
  const submit = useForwardMessage()
  const inputRef = useRef(null)
  return (
    <Composer.Provider
      state={state}
      actions={{ update: setState, submit }}
      meta={{ inputRef }}
    >
      {children}
    </Composer.Provider>
  )
}

// Qualquer componente dentro do Provider acede ao state
function ForwardDialog() {
  return (
    <ForwardProvider>
      <Dialog>
        <ForwardComposer />
        <MessagePreview />
        <ForwardButton />
      </Dialog>
    </ForwardProvider>
  )
}

function ForwardButton() {
  const { actions } = use(ComposerContext)
  return <Button onPress={actions.submit}>Forward</Button>
}
```

**Principio chave:** O boundary do Provider e o que importa, nao o nesting visual.

---

## Regra #4: Interface Generica para Dependency Injection (HIGH)

```tsx
// Definir interface generica: state + actions + meta
interface ComposerContextValue {
  state: { input: string; attachments: Attachment[]; isSubmitting: boolean }
  actions: { update: (fn: (s: State) => State) => void; submit: () => void }
  meta: { inputRef: React.RefObject<TextInput> }
}

// Multiplos providers implementam a MESMA interface
function ChannelProvider({ channelId, children }) {
  const { state, update, submit } = useGlobalChannel(channelId)
  return <Composer.Provider state={state} actions={{ update, submit }}>{children}</Composer.Provider>
}

function ForwardProvider({ children }) {
  const [state, setState] = useState(initialState)
  return <Composer.Provider state={state} actions={{ update: setState, submit: forward }}>{children}</Composer.Provider>
}

// O mesmo Composer.Input funciona com AMBOS os providers
```

**Principio:** UI = pecas reutilizaveis. State = injectado pelo provider. Trocar provider, manter UI.

---

## Regra #5: Children > Render Props (MEDIUM)

```tsx
// NAO: Render props (inflexivel)
<Composer
  renderHeader={() => <Header />}
  renderFooter={() => <><Formatting /><Emojis /></>}
/>

// SIM: Children (composicao natural)
<Composer.Frame>
  <Header />
  <Composer.Input />
  <Composer.Footer>
    <Formatting />
    <Emojis />
  </Composer.Footer>
</Composer.Frame>

// Excepcao: render props quando parent passa dados
<List data={items} renderItem={({ item }) => <Item item={item} />} />
```

---

## Regra #6: React 19 APIs (MEDIUM)

```tsx
// React 19: ref como prop normal (sem forwardRef)
function Input({ ref, ...props }: Props & { ref?: React.Ref<HTMLInputElement> }) {
  return <input ref={ref} {...props} />
}

// React 19: use() em vez de useContext()
const value = use(MyContext) // pode ser chamado condicionalmente
```

---

## Checklist Composicao

- [ ] Zero boolean props para variantes (usar componentes explicitos)
- [ ] Compound components com context partilhado
- [ ] State em Provider (nao dentro do componente UI)
- [ ] Interface generica (state/actions/meta)
- [ ] Children para composicao, render props so para data passthrough
- [ ] React 19: `use()` e ref como prop
