# React Patterns ## State Management ### Local State with useState ```tsx import { useState } from "react" function Counter() { const [count, setCount] = useState(0) return ( Count: {count} setCount(c => c - 1)}> - setCount(c => c + 1)}> + ) } ``` ### Complex State with useReducer ```tsx import { useReducer } from "react" type State = { items: string[] selectedIndex: number } type Action = | { type: "ADD_ITEM"; item: string } | { type: "REMOVE_ITEM"; index: number } | { type: "SELECT"; index: number } function reducer(state: State, action: Action): State { switch (action.type) { case "ADD_ITEM": return { ...state, items: [...state.items, action.item] } case "REMOVE_ITEM": return { ...state, items: state.items.filter((_, i) => i !== action.index), } case "SELECT": return { ...state, selectedIndex: action.index } } } function ItemList() { const [state, dispatch] = useReducer(reducer, { items: [], selectedIndex: 0, }) // Use state and dispatch... } ``` ### Context for Global State ```tsx import { createContext, useContext, useState, ReactNode } from "react" type Theme = "dark" | "light" const ThemeContext = createContext<{ theme: Theme setTheme: (theme: Theme) => void } | null>(null) function ThemeProvider({ children }: { children: ReactNode }) { const [theme, setTheme] = useState("dark") return ( {children} ) } function useTheme() { const context = useContext(ThemeContext) if (!context) throw new Error("useTheme must be used within ThemeProvider") return context } // Usage function App() { return ( ) } function ThemedBox() { const { theme } = useTheme() return ( Current theme: {theme} ) } ``` ## Focus Management ### Focus State ```tsx import { useState } from "react" import { useKeyboard } from "@opentui/react" function FocusableForm() { const [focusIndex, setFocusIndex] = useState(0) const fields = ["name", "email", "message"] useKeyboard((key) => { if (key.name === "tab") { setFocusIndex(i => (i + 1) % fields.length) } if (key.shift && key.name === "tab") { setFocusIndex(i => (i - 1 + fields.length) % fields.length) } }) return ( {fields.map((field, i) => ( ))} ) } ``` ### Ref-based Focus ```tsx import { useRef, useEffect } from "react" function AutoFocusInput() { const inputRef = useRef(null) useEffect(() => { // Focus on mount inputRef.current?.focus() }, []) return } ``` ## Keyboard Navigation ### Global Shortcuts ```tsx import { useKeyboard } from "@opentui/react" function App() { useKeyboard((key) => { // Quit on Escape or Ctrl+C if (key.name === "escape" || (key.ctrl && key.name === "c")) { process.exit(0) } // Toggle help on ? if (key.name === "?" || (key.shift && key.name === "/")) { setShowHelp(h => !h) } // Vim-style navigation if (key.name === "j") moveDown() if (key.name === "k") moveUp() }) return {/* ... */} } ``` ### Component-level Shortcuts ```tsx function Editor() { const [mode, setMode] = useState<"normal" | "insert">("normal") useKeyboard((key) => { if (mode === "normal") { if (key.name === "i") setMode("insert") if (key.name === "escape") setMode("normal") } else { if (key.name === "escape") setMode("normal") // Handle text input in insert mode } }) return ( Mode: {mode}