Skip to content

Preact Props and State — Managing Data in Preact Components

DodaTech Updated 2026-06-28 4 min read

Learn how Preact manages data flow through props and state, with comparisons to React's model and Preact-specific considerations for the 3kB library.

In this lesson, you'll understand props for parent-to-child communication, state for component-local data, and how both work together in Preact applications.

What You'll Learn

How to pass props from parent to child, manage local state with useState, lift state up when needed, and handle prop drilling in component trees.

Why It Matters

Data management is the core of any interactive application. Props provide a one-way data flow that makes applications predictable, while state enables dynamic behavior.

Real-World Use

DodaZIP's file list component uses props to receive file data from its parent and state to track which files are selected for extraction, demonstrating both prop-based data flow and local UI state.

flowchart LR
    A[Parent Component] -->|Props| B[Child Component]
    B -->|State| C[Local UI State]
    B -->|Callback Props| D[Parent Event Handler]
    style A fill:#673ab8,color:#fff

Props in Functional Components

Props are passed as the first argument to functional components:

function Profile({ username, age, isVerified }) {
  return (
    <div>
      <h3>{username}</h3>
      <p>Age: {age}</p>
      {isVerified && <span>Verified account</span>}
    </div>
  );
}

function App() {
  return <Profile username="alice" age={28} isVerified />;
}

Output: A profile card showing Alice's details with a "Verified account" badge. Props are destructured directly in the function signature.

State with useState

Preact's useState hook works identically to React's:

import { useState } from 'preact/hooks';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(count - 1)}>Decrement</button>
    </div>
  );
}

Output: A counter display with increment and decrement buttons. The useState hook returns the current state and an updater function.

State in Class Components

Class components use this.state and this.setState():

import { Component } from 'preact';

class Toggle extends Component {
  constructor() {
    super();
    this.state = { isOn: false };
  }

  handleToggle = () => {
    this.setState(prev => ({ isOn: !prev.isOn }));
  };

  render() {
    return (
      <button onClick={this.handleToggle}>
        {this.state.isOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

Output: A toggle button that switches between ON and OFF. The functional updater prev => ({ ... }) ensures correct state transitions.

Lifting State Up

When multiple components need shared state, lift it to the nearest common ancestor:

function TemperatureInput({ scale, temperature, onTemperatureChange }) {
  return (
    <div>
      <label>{scale}:</label>
      <input type="number" value={temperature}
        onChange={e => onTemperatureChange(e.target.value)} />
    </div>
  );
}

function Calculator() {
  const [temp, setTemp] = useState('');
  const [scale, setScale] = useState('celsius');

  const handleCelsiusChange = (value) => {
    setScale('celsius');
    setTemp(value);
  };

  const handleFahrenheitChange = (value) => {
    setScale('fahrenheit');
    setTemp(value);
  };

  const celsius = scale === 'fahrenheit' ? ((temp - 32) * 5 / 9) : temp;
  const fahrenheit = scale === 'celsius' ? (temp * 9 / 5 + 32) : temp;

  return (
    <div>
      <TemperatureInput scale="Celsius" temperature={celsius}
        onTemperatureChange={handleCelsiusChange} />
      <TemperatureInput scale="Fahrenheit" temperature={fahrenheit}
        onTemperatureChange={handleFahrenheitChange} />
    </div>
  );
}

Output: Two temperature inputs that stay in sync. State lives in the Calculator parent and flows down through props.

Common Mistakes

  1. Mutating state directly: Never do state.count = 1. Always use setState() or the setCount() updater function.
  2. Forgetting that setState is asynchronous: State updates are batched. Reading this.state immediately after setState() gives the old value.
  3. Using props to initialize state incorrectly: useState(props.value) only uses the prop on first render. Changes to props.value won't update state.
  4. Passing too many props: If a component has 10+ props, consider grouping related props into an object or splitting the component.
  5. Not using callback props for child-to-parent communication: Children can't modify parent state directly. Pass a callback function as a prop instead.

Practice Questions

  1. What is the difference between props and state? Answer: Props are passed from parent to child and are read-only. State is local to a component and can be updated with setState() or useState updaters.

  2. How do you pass data from a child back to a parent? Answer: The parent passes a callback function as a prop. The child calls it with the data when needed.

  3. What happens when you call setState() in a class component? Answer: Preact merges the new state with the existing state and schedules a re-render of the component.

  4. Can you use useState in class components? Answer: No. Hooks like useState only work in functional components. Use this.state and this.setState() in class components.

Challenge

Create a form with multiple inputs (name, email, age) managed by a single useState object. Add validation that disables the submit button when fields are empty.

Mini Project

Build a simple shopping cart component with a product list and cart summary. Products are passed as props, cart state lives in the parent, and add/remove callbacks update the cart.

FAQ

Does Preact support `useReducer`?

: Yes. useReducer is available in preact/hooks and works identically to React's version for complex state logic.

Can I use `useState` with objects?

: Yes. Unlike class setState which merges, useState replaces the entire value. Spread the previous state: setState(prev => ({ ...prev, newKey: value })).

What is the prop drilling problem?

: Passing props through many intermediary components that don't use them. Context is the solution for deeply nested prop passing.

Does Preact batch state updates?

: Yes. Multiple setState() calls in the same event handler are batched into a single re-render for performance.

What's Next

Learn about Preact Event Handling to understand how Preact handles user interactions with its event system.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro