ESC

Type to search the knowledge base.

Function Components

Function components as UI functions of props and state: hooks, purity under concurrent render, and how they differ from classes.

beginner3 min read
  • react
  • function-components

A function component is a JavaScript function that accepts props and returns React elements describing the UI. With Hooks, functions own state, effects, and refs — the modern default for almost all new React UI.

function Greeting({ name }) {
  return <p>Hello, {name}</p>;
}

React calls your function during render. You return a description; React decides what to change in the DOM during commit. Treat the body as pure with respect to props and state: same inputs should produce the same element tree (unless you deliberately accept non-determinism).

Docs: Your First Component, Passing Props.

Anatomy with hooks

import { useState, useEffect } from 'react';

function UserCard({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    let cancelled = false;
    fetch(`/api/users/${userId}`)
      .then((r) => r.json())
      .then((data) => {
        if (!cancelled) setUser(data);
      });
    return () => {
      cancelled = true;
    };
  }, [userId]);

  if (!user) return <p>Loading…</p>;
  return (
    <article>
      <h2>{user.name}</h2>
      <p>{user.bio}</p>
    </article>
  );
}

Conventions that matter:

  1. Capitalized name — UserCard, not userCard. Lowercase is treated as an intrinsic host tag.
  2. Props object — one argument; destructure for clarity.
  3. Hooks at the top level — see Rules of Hooks.
  4. No direct DOM mutation during render — leave that to effects or refs after commit.

Function versus class

Concern Function + Hooks Class
State useState / useReducer this.state
Side effects useEffect / useLayoutEffect lifecycle methods
Instance methods rare; callbacks + refs this.handleClick
Error boundaries not available in functions componentDidCatch
Mental model composition-friendly more boilerplate

New code should be functions unless you need an error boundary class or are maintaining a legacy tree. See Error Boundaries.

Purity and concurrent rendering

React may call your function multiple times before commit (Strict Mode double-invoke in development, concurrent interruptions). That is why side effects during render are bugs:

// Bad: side effect during render
function Bad({ id }) {
  analytics.track('view', id);
  return <div />;
}

// Good: effect after paint
function Good({ id }) {
  useEffect(() => {
    analytics.track('view', id);
  }, [id]);
  return <div />;
}

Local pure calculations during render are fine. Avoid derived state anti-patterns that copy props into state.

Props are read-only

Never mutate props. To change data, lift state or call a callback the parent provided:

function Toggle({ on, onChange }) {
  return (
    <button type="button" aria-pressed={on} onClick={() => onChange(!on)}>
      {on ? 'On' : 'Off'}
    </button>
  );
}

Interview out-loud

“Function components are pure-ish functions from props and state to elements. Hooks attach state and effects to the fiber. React may re-run the function without committing, so keep render free of side effects. Prefer functions over classes except for error boundaries.”

Further reading

Edge cases worth rehearsing

Interviewers and production incidents cluster around the same edges: first render versus update, empty and loading states, Strict Mode double setup, concurrent interruptions, and what happens when identity (key, route params, user id) changes mid-edit. Walk one concrete user journey end-to-end — open, edit, navigate away, come back — and say which state survives.

Prefer fixing data flow and ownership before reaching for memoization or micro-optimizations. Prefer event handlers over effects when a user action is the trigger. Prefer deriving values during render over mirroring props into state. Prefer stable list keys from business ids. Measure with the profiler when performance is the claim.

When you cite an API, mention one failure mode: abort on unmount, serializable props across server/client boundaries, focus restoration for dialogs, or cache invalidation after a mutation. Specific beats generic every time.

Related guides