Preact Props and State — Managing Data in Preact Components
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
- Mutating state directly: Never do
state.count = 1. Always usesetState()or thesetCount()updater function. - Forgetting that setState is asynchronous: State updates are batched. Reading
this.stateimmediately aftersetState()gives the old value. - Using props to initialize state incorrectly:
useState(props.value)only uses the prop on first render. Changes toprops.valuewon't update state. - Passing too many props: If a component has 10+ props, consider grouping related props into an object or splitting the component.
- 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
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()oruseStateupdaters.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.
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.Can you use
useStatein class components? Answer: No. Hooks likeuseStateonly work in functional components. Usethis.stateandthis.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
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