UI Library

React

React is the component library that made declarative UI mainstream. Describe what the screen should look like for a given state, and let React work out how to update it.

intermediate16 min readUpdated Sep 15, 2026
Counter.jsx
jsx
// Counter.jsx
import { useState } from "react";

export function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount((c) => c + 1)}>
      Clicked {count} times
    </button>
  );
}
Released
2013, by Facebook
Model
Declarative components
Language
JavaScript + JSX
State
useState and friends
Data flow
One-way, top to bottom
Ecosystem
Next.js, React Router, RSC

Why it matters

Why React won

Everything is a component

UIs are built from small, reusable functions that each own a piece of the screen and can be composed freely.

Declarative updates

You describe the UI for the current state, and React figures out the minimal DOM changes to get there.

Huge ecosystem

Next.js, React Native, React Router and thousands of libraries make React a platform, not just a view layer.

The big picture

The three ideas behind React

Components, state and a one-way data flow. Everything else in React is built from those three.

Components

Building blocks

Functions that return JSX, accept props and can be nested, reused and composed.

State

Change

Data owned by a component. When state updates, React re-renders and the UI reflects the new value.

One-way data flow

Predictability

Data moves down through props and changes travel up through callbacks, which keeps behaviour easy to trace.

React at a glance

The core of React

Components & JSX

Functions returning markup, written in a syntax that looks like HTML inside JavaScript.

Props

Read-only inputs passed from parent to child, the way arguments work for functions.

State

useState holds values that change over time and triggers a re-render when updated.

Effects

useEffect runs side effects such as fetching data or subscribing to events.

Context

Share values across a tree without threading props through every level.

Hooks

Functions that let components use state and lifecycle features, and the basis of custom hooks.

A short history

How React reshaped the front end

  1. 2013

    Open sourced

    Facebook releases React, introducing the virtual DOM and JSX to a skeptical community.

    13
  2. 2015

    React Native

    The component model extends to iOS and Android, proving it is not tied to the DOM.

    15
  3. 2019

    Hooks

    useState and useEffect let function components own state and replace most class components.

    19
  4. 2022

    Concurrent React

    React 18 brings automatic batching, transitions and streaming server rendering.

    22
  5. Today

    Server Components

    React Server Components move rendering to the server and reshape how data is fetched.

    Today

The complete guide

React: Everything you need to know

What is React?

React is a JavaScript library for building user interfaces from components. A component is a function that returns markup, and you compose components together to build a page. Instead of telling the browser how to change the DOM step by step, you describe what the UI should look like for the current data, and React works out the updates.

That shift is called declarative rendering, and it is the reason React felt different in 2013. You stop writing “find this element, change its text, toggle that class” and start writing “given this state, here is the screen”. The messy part — diffing and updating the DOM efficiently — becomes React’s job.

Components and JSX

A React component is a function whose name starts with a capital letter and that returns JSX.

// Welcome.jsx
function Welcome({ name }) {
  return <h1>Hello, {name}!</h1>;
}

export default function App() {
  return (
    <main>
      <Welcome name="Ada" />
      <Welcome name="Grace" />
    </main>
  );
}

JSX looks like HTML but is JavaScript. Curly braces embed expressions, and the compiler translates each element into a function call. Because components are just functions, you can compose them, nest them and reuse them the same way you reuse any other function.

Props

Props are the inputs to a component. They flow down from parent to child and are read-only — a child must never mutate its props.

// Card.jsx
function Card({ title, children, variant = "default" }) {
  return (
    <article className={`card card--${variant}`}>
      <h3>{title}</h3>
      {children}
    </article>
  );
}

The children prop is whatever you nest between the opening and closing tags, which makes components composable wrappers. Default values let callers omit props that usually stay the same.

State with useState

Props are fixed for a given render. State is data a component owns and can change over time. The useState hook creates a state value and a setter.

// Search.jsx
import { useState } from "react";

function Search({ onSearch }) {
  const [query, setQuery] = useState("");

  return (
    <form onSubmit={(e) => { e.preventDefault(); onSearch(query); }}>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
    </form>
  );
}

Calling the setter schedules a re-render with the new value. State updates are asynchronous and batched, and they replace rather than merge, so always create a new object or array when updating structured state.

// update.jsx
setUser((prev) => ({ ...prev, name: "Grace" }));
setItems((prev) => [...prev, newItem]);

Using the updater function form keeps you safe when the next value depends on the previous one.

Rendering lists and conditions

React has no template language for loops and branches — you use plain JavaScript.

// List.jsx
function List({ items }) {
  if (items.length === 0) return <p>Nothing here yet.</p>;

  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.label}</li>
      ))}
    </ul>
  );
}

The key prop is required for list items. Give it a stable, unique value from your data so React can match items correctly across renders. The ternary operator and && cover inline conditions, though early returns often read better.

Events

React events use camelCase props and receive a synthetic event object.

// Button.jsx
<button
  onClick={(event) => {
    event.preventDefault();
    submit();
  }}
>
  Save
</button>

Passing a function to the prop is important — onClick={submit()} would call it immediately during render. When a handler needs an argument, wrap it in an arrow function.

Effects with useEffect

useEffect synchronises your component with systems outside React: network requests, subscriptions, timers and direct DOM work.

// Users.jsx
import { useEffect, useState } from "react";

function Users() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    const controller = new AbortController();

    fetch("/api/users", { signal: controller.signal })
      .then((res) => res.json())
      .then(setUsers)
      .catch((err) => {
        if (err.name !== "AbortError") console.error(err);
      });

    return () => controller.abort();
  }, []);

  return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}

The dependency array controls when the effect re-runs: an empty array runs once after mount, a list of values runs when any of them change, and no array runs after every render. The returned function is cleanup, which runs before the next effect and on unmount. Always clean up subscriptions and in-flight requests.

Context and refs

Context shares a value with a whole subtree without prop drilling.

// theme.jsx
const ThemeContext = createContext("light");

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Button() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Click</button>;
}

Refs hold a mutable value or a DOM node that should not trigger a re-render.

// focus.jsx
const inputRef = useRef(null);
useEffect(() => inputRef.current?.focus(), []);
return <input ref={inputRef} />;

Data flow and lifting state

React data flows in one direction. When two siblings need to share state, you lift it to their closest common parent and pass the value down as a prop and the setter down as a callback. This keeps a single source of truth and makes the flow of change easy to follow.

For deeper trees, context or a dedicated state library such as Zustand or Redux may be worth the extra machinery. Reach for them when prop passing becomes painful, not before.

Hooks and custom hooks

Hooks are functions that let components tap into React features. They must be called at the top level, never inside conditions or loops. Once you understand them, you can extract shared logic into a custom hook.

// useFetch.js
function useFetch(url) {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    let active = true;
    fetch(url)
      .then((res) => res.json())
      .then((json) => active && setData(json))
      .catch((err) => active && setError(err));
    return () => { active = false; };
  }, [url]);

  return { data, error };
}

A custom hook is just a function whose name starts with use and that calls other hooks. It shares logic, not state — each component that uses it gets its own independent copy.

Best practices

  • Keep components small and focused on one responsibility.
  • Compute derived values during render instead of storing them in state.
  • Use the updater form of a setter when the next value depends on the previous one.
  • Give every list item a stable key from your data.
  • Clean up effects, especially subscriptions and pending requests.
  • Lift state only as far as it needs to go.
  • Extract repeated logic into custom hooks.
  • Reach for memoisation (useMemo, useCallback, memo) only after measuring a real problem.

Common mistakes

  • Mutating state directly instead of creating a new value.
  • Using the array index as a key and breaking reordering.
  • Putting derived data in state and syncing it with an effect.
  • Forgetting the dependency array and causing infinite loops.
  • Calling a hook conditionally and breaking the rules of hooks.
  • Optimising with memoisation before there is a performance issue.

Where to go next

React is the view layer; Next.js adds routing, data fetching and server rendering on top. Compare the model with Vue and Svelte, and strengthen your foundations with JavaScript and TypeScript. The interactive React tutorial walks through the same ideas step by step.

Derived values

If a value can be computed from props or state, compute it during render. Storing it in state invites bugs and extra renders.

Prefer
function Cart({ items }) {
  const total = items.reduce(
    (sum, i) => sum + i.price,
    0,
  );
  return <p>Total: {total}</p>;
}
Avoid
function Cart({ items }) {
  const [total, setTotal] = useState(0);
  useEffect(() => {
    setTotal(items.reduce(
      (s, i) => s + i.price, 0,
    ));
  }, [items]);
  return <p>Total: {total}</p>;
}

Keys in lists

A stable key lets React match items between renders. Using the index breaks reordering and editing.

Prefer
{todos.map((todo) => (
  <Todo key={todo.id} todo={todo} />
))}
Avoid
{todos.map((todo, i) => (
  <Todo key={i} todo={todo} />
))}

FAQ

Frequently asked questions

Keep learning

Related topics from the roadmap.

$ start learning

Ready to start learning React?

Our interactive tutorial walks you through React step by step — with quizzes and real code you can run in the browser.