Skip to content

React Basics

Before building real features, you need a mental model of how React applications are structured. This lesson covers the component tree, one-way data flow, JSX, and the difference between props and state.

The Component Tree and One-Way Data Flow

A React application is a tree of components. At the root sits something like <App />, which renders child components, which may render their own children. Data flows down through props; events and callbacks flow up so parents can react to child interactions.

When state or props change, React re-runs the affected component functions and compares the new output to the previous render. Only the differences are applied to the real DOM — this process is called reconciliation.

function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <Counter count={count} onIncrement={() => setCount(c => c + 1)} />
    </div>
  );
}

Parent App owns the state; child Counter receives it via props and notifies the parent through a callback.

Props vs State

// Props — passed in, read-only
function Greeting({ name }) {
  return <p>Hello, {name}</p>;
}

// State — owned locally, updatable
function Counter() {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>{n}</button>;
}
  • Props are inputs from a parent; never mutate them inside the child.
  • State is private to a component (or lifted to a shared ancestor).
  • Changing state triggers a re-render of that component and its descendants.
  • Use descriptive component and prop names — they are your primary documentation.

React Basics Cheat Sheet

Quick reference for the foundational concepts every React developer uses daily.

Term Meaning
Component Function that returns UI
JSX HTML-like syntax embedded in JavaScript
Props Read-only configuration passed to a component
State Data that changes over time inside a component
Re-render React re-executes a component when inputs change
Reconciliation Diffing virtual DOM to update real DOM efficiently
One-way flow Data down via props, events up via callbacks

The Virtual DOM and Reconciliation

React builds a lightweight in-memory representation of the UI (the virtual DOM) on each render. It compares the new tree to the previous one and computes the minimal set of DOM operations needed. You rarely touch the DOM directly — React handles it.

This does not mean React is always faster than manual DOM updates; it means predictable, declarative code with efficient batching. React 18's concurrent rendering can pause and resume work for smoother interactions.

Typical Project Structure

A Vite + React project usually organizes code like this:

src/
  main.jsx       # entry — createRoot and render App
  App.jsx        # root component
  components/    # reusable UI pieces
  hooks/         # custom hooks
  pages/         # route-level components
  assets/        # images, fonts

Exact layout varies by team, but separating components, hooks, and pages is common.

Common Mistakes

  • Mutating state directly instead of calling the setter from useState.
  • Passing too many props through many layers (prop drilling) without considering context or composition.
  • Creating components inside other components, which remounts them every render.
  • Confusing re-renders with DOM updates — not every re-render touches the DOM.

Key Takeaways

  • React apps are trees of components with one-way data flow.
  • Props are read-only inputs; state is mutable data that triggers re-renders.
  • React reconciles virtual DOM changes to update the real DOM efficiently.
  • Organize code into components, hooks, and pages for maintainability.

Pro Tip

When debugging, ask: "Which component owns this data?" If two siblings need the same state, lift it to their closest common parent.