Components
function Button({ label }) { return <button>{label}</button>; }Function componentexport default ButtonDefault exportexport { Button }Named export<Button label="Click me" />Self-closing JSX with prop<Button label="OK">child</Button>Component with childrenclassName="text-red"CSS class in JSX (not class)htmlFor="email"label attribute in JSX (not for){/* comment */}JSX comment syntaxconst el = <h1>Hello</h1>JSX expression - compiles to React.createElement<>{children}<>Fragment - multiple children without wrapper div<React.Fragment key={id}>{children}</React.Fragment>Fragment with key propstyle={{ color: "red", fontSize: 16 }}Inline styles as object - camelCase propertiesdangerouslySetInnerHTML={{ __html: html }}Render raw HTML - use with cautionProps
function Card({ title, body }) { }Destructure propsfunction Card({ title = "Untitled" }) { }Default prop valuefunction Card(props) { props.title }Access via props objectfunction Wrap({ children }) { return <div>{children}</div>; }Render children<Button {...obj} />Spread object as props<button disabled={isDisabled}>Boolean attribute - omit value when true{show && <Modal />}Conditionally render - short-circuit{show ? <A /> : <B />}Ternary conditional renderPropTypes.string.isRequiredRuntime prop type checking (prop-types package)useState
const [count, setCount] = useState(0)Declare state with initial valuesetCount(5)Set state to a new valuesetCount(n => n + 1)Functional update - use when new state depends on oldconst [user, setUser] = useState(null)Nullable stateconst [items, setItems] = useState([])Array statesetItems(prev => [...prev, newItem])Append to array statesetItems(prev => prev.filter(i => i.id !== id))Remove from array statesetUser(prev => ({ ...prev, name: "Alice" }))Update object state fielduseState(() => expensiveInit())Lazy initial state - function runs only onceuseEffect
useEffect(() => { ... })Run after every renderuseEffect(() => { ... }, [])Run once after mount (empty deps)useEffect(() => { ... }, [id])Run when id changesuseEffect(() => { return () => cleanup(); }, [])Cleanup function - runs before next effect or unmountuseEffect(() => { let active = true; fetch(...).then(d => { if (active) setData(d); }); return () => { active = false; }; }, [id])Cancel stale async effectuseLayoutEffect(() => { ... }, [])Like useEffect but fires synchronously after DOM mutationsuseRef & DOM
const ref = useRef(null)Create a ref - .current holds the value<input ref={ref} />Attach ref to DOM elementref.current.focus()Call DOM method on refconst timerRef = useRef(null); timerRef.current = setInterval(...)Store mutable value without triggering re-renderuseImperativeHandle(ref, () => ({ focus }))Expose methods to parent refconst cb = useCallback(() => doSomething(id), [id])Memoize function - new reference only when deps changeconst val = useMemo(() => expensive(data), [data])Memoize computed value - recalculate only when deps changeContext
const ThemeCtx = createContext("light")Create context with default value<ThemeCtx.Provider value={theme}>Provide value to all descendantsconst theme = useContext(ThemeCtx)Consume context value in componentfunction useTheme() { return useContext(ThemeCtx); }Custom hook wrapping useContextuseReducer
const [state, dispatch] = useReducer(reducer, init)Use reducer for complex state logicdispatch({ type: "increment" })Dispatch an actiondispatch({ type: "setUser", payload: user })Dispatch with payloadfunction reducer(state, action) { switch (action.type) { case "inc": return { ...state, n: state.n + 1 }; default: return state; } }Reducer functionuseReducer(reducer, null, () => initialState)Lazy initial state via init functionLists & Keys
{items.map(item => <li key={item.id}>{item.name}</li>)}Render list - key must be unique and stablekey={item.id}Use stable ID - avoid array index unless list is static{items.filter(i => i.active).map(i => <Row key={i.id} {...i} />)}Filter then mapEvents
<button onClick={handleClick}>Click handler<button onClick={() => handleClick(id)}>Pass arguments via arrow function<input onChange={e => setValue(e.target.value)} />Controlled input - onChange updates state<form onSubmit={e => { e.preventDefault(); ... }}>Prevent default form submission<div onKeyDown={e => e.key === "Enter" && submit()}>Key events<div onMouseEnter={...} onMouseLeave={...}>Mouse enter/leavee.stopPropagation()Stop event bubbling to parent<input value={value} onChange={e => setValue(e.target.value)} />Controlled input pattern<input defaultValue="init" />Uncontrolled input with initial valueCustom Hooks & Patterns
function useFetch(url) { const [data, setData] = useState(null); useEffect(() => { fetch(url).then(r => r.json()).then(setData); }, [url]); return data; }Custom hook - name must start with useconst data = useFetch("/api/users")Consume custom hookconst [value, setValue] = useLocalStorage("key", init)Common pattern: sync state with localStorageReact.memo(Component)Memoize component - skip re-render if props unchangedReact.memo(Component, (prev, next) => prev.id === next.id)Custom comparison for React.memoconst LazyModal = React.lazy(() => import("./Modal"))Lazy-load component<Suspense fallback={<Spinner />}><LazyModal /></Suspense>Wrap lazy component with Suspenseconst id = useId()Generate unique ID for accessibility (React 18+)useTransition / useDeferredValueDefer non-urgent state updates (React 18+)createPortal(children, document.body)Render children into a different DOM node