React Cheatsheet

Components and JSX

Use this React reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Function Components

The only modern component type. A function that accepts props and returns JSX (or null).

// Declaration
function Button({ label, onClick }) {
  return <button onClick={onClick}>{label}</button>;
}

// Arrow function
const Button = ({ label, onClick }) => (
  <button onClick={onClick}>{label}</button>
);

// Arrow with block body (needed for multiple statements)
const Button = ({ label, onClick }) => {
  const cls = label.length > 10 ? 'long' : 'short';
  return <button className={cls} onClick={onClick}>{label}</button>;
};

JSX Expressions and Embedding Values

const name = 'Alice';
const count = 42;
const isAdmin = true;

function Profile() {
  return (
    <div>
      {/* strings, numbers, expressions */}
      <p>{name}</p>
      <p>{count * 2}</p>
      <p>{isAdmin ? 'Admin' : 'User'}</p>

      {/* function calls */}
      <p>{name.toUpperCase()}</p>

      {/* arrays render each element */}
      <ul>{['a', 'b', 'c'].map(x => <li key={x}>{x}</li>)}</ul>

      {/* null, undefined, false, true render nothing */}
      {false}
      {null}
      {undefined}

      {/* objects are NOT valid children — use JSON.stringify or access a property */}
      {/* WRONG: {myObj} */}
      {JSON.stringify({ a: 1 })}
    </div>
  );
}

Fragments

Wrap multiple siblings without adding a DOM node.

import { Fragment } from 'react';

// Short syntax (no props)
function Row() {
  return (
    <>
      <td>Name</td>
      <td>Age</td>
    </>
  );
}

// Long form — needed when passing key to the fragment
function List({ items }) {
  return items.map(item => (
    <Fragment key={item.id}>
      <dt>{item.term}</dt>
      <dd>{item.def}</dd>
    </Fragment>
  ));
}

JSX Attribute Rules

HTML attributeJSX equivalent
classclassName
forhtmlFor
tabindextabIndex
readonlyreadOnly
maxlengthmaxLength
crossorigincrossOrigin
enctypeencType
onclickonClick
style="color:red"style={{ color: 'red' }}
checked (static)defaultChecked (uncontrolled)
value (static)defaultValue (uncontrolled)
// Spreading an object as props
const attrs = { id: 'btn', disabled: true, 'aria-label': 'Save' };
const el = <button {...attrs}>Save</button>;

// aria-* and data-* use their original kebab-case names
const el2 = <div aria-hidden="true" data-testid="box" />;

Children

// children prop — anything between opening and closing tags
function Card({ children, title }) {
  return (
    <div className="card">
      <h2>{title}</h2>
      {children}
    </div>
  );
}

// Usage
<Card title="Info">
  <p>Some content</p>
  <p>More content</p>
</Card>

// Children utilities — LEGACY: react.dev discourages Children.* and
// cloneElement (fragile, break with Fragments/wrappers). Prefer passing
// props/JSX explicitly, render props, or context. Shown for reading old code:
import { Children, cloneElement, isValidElement } from 'react';

Children.count(children)           // number of children
Children.toArray(children)         // flat array, keys reassigned
Children.map(children, fn)         // map without losing keys
Children.forEach(children, fn)     // iterate
Children.only(children)            // assert exactly one child, return it

isValidElement(obj)                // true if obj is a React element

// Clone and inject extra props
cloneElement(element, { extraProp: 'value' })

Composition Patterns

// Slot pattern via named props
function Layout({ header, sidebar, children }) {
  return (
    <div className="layout">
      <header>{header}</header>
      <aside>{sidebar}</aside>
      <main>{children}</main>
    </div>
  );
}

// Usage
<Layout
  header={<nav>Nav</nav>}
  sidebar={<SideMenu />}
>
  <PageContent />
</Layout>

// Render props
function Mouse({ render }) {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  return (
    <div onMouseMove={e => setPos({ x: e.clientX, y: e.clientY })}>
      {render(pos)}
    </div>
  );
}
<Mouse render={({ x, y }) => <p>{x}, {y}</p>} />

Lazy Loading Components

import { lazy, Suspense } from 'react';

// Dynamic import — code-split at this boundary
const HeavyChart = lazy(() => import('./HeavyChart'));

function Dashboard() {
  return (
    <Suspense fallback={<p>Loading chart…</p>}>
      <HeavyChart />
    </Suspense>
  );
}

Portals

Render children into a different DOM node outside the parent hierarchy.

import { createPortal } from 'react-dom';

function Modal({ children }) {
  return createPortal(
    <div className="modal-overlay">{children}</div>,
    document.getElementById('modal-root')  // target DOM node
  );
}

Display Names and DevTools

// Named function declarations get a display name automatically
function MyComponent() { return null; }

// Arrow functions assigned to a const also infer the name
const MyComponent = () => null;

// Set explicitly (useful for HOCs and wrappers)
const WrappedComponent = React.memo(MyComponent);
WrappedComponent.displayName = 'WrappedMyComponent';

Strict Mode Behavior

import { StrictMode } from 'react';

// In development only:
// - Renders components twice to detect side-effects in render
// - Calls effects twice (mount → unmount → remount) to verify cleanup
// - Warns about deprecated APIs
// Has zero effect in production builds

<StrictMode>
  <App />
</StrictMode>

ref as a Prop (React 19) and forwardRef (legacy)

Since React 19, function components receive ref as a regular prop — no wrapper needed.

// React 19 — just destructure ref like any other prop
function FancyInput({ label, ref }) {
  return (
    <label>
      {label}
      <input ref={ref} />
    </label>
  );
}

// Usage (identical in both patterns)
function Form() {
  const inputRef = useRef(null);
  return <FancyInput label="Name" ref={inputRef} />;
}

forwardRef is the React ≤18 pattern and is deprecated in React 19 (it still works, but new code should take ref as a prop):

// Legacy (React ≤18) — ref arrives as a second argument via forwardRef
import { forwardRef } from 'react';

const FancyInput = forwardRef(function FancyInput({ label }, ref) {
  return (
    <label>
      {label}
      <input ref={ref} />
    </label>
  );
});

Error Boundaries

Catch render errors in a subtree and show a fallback instead of unmounting the whole app. Still class-only — there is no hook equivalent; most apps use the react-error-boundary package.

// Class implementation
import { Component } from 'react';

class ErrorBoundary extends Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };            // render the fallback next pass
  }

  componentDidCatch(error, info) {
    logError(error, info.componentStack); // report to your error service
  }

  render() {
    if (this.state.hasError) return this.props.fallback;
    return this.props.children;
  }
}

<ErrorBoundary fallback={<p>Something went wrong.</p>}>
  <Profile />
</ErrorBoundary>
// react-error-boundary (npm install react-error-boundary)
import { ErrorBoundary } from 'react-error-boundary';

<ErrorBoundary
  fallbackRender={({ error, resetErrorBoundary }) => (
    <div role="alert">
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  )}
  onError={(error, info) => logError(error, info)}
>
  <Profile />
</ErrorBoundary>

Error boundaries do not catch: event handler errors (use try/catch), async code, SSR errors, or errors thrown in the boundary itself. Place one near the root plus finer-grained ones around risky widgets.

memo — Skip Re-renders

import { memo } from 'react';

// Component only re-renders if props change (shallow comparison)
const ExpensiveList = memo(function ExpensiveList({ items }) {
  return <ul>{items.map(i => <li key={i.id}>{i.name}</li>)}</ul>;
});

// Custom comparison function (optional)
const Item = memo(
  function Item({ data }) { return <div>{data.name}</div>; },
  (prevProps, nextProps) => prevProps.data.id === nextProps.data.id
);