Preact - Component Types
Quick overview of Preact´s v10 most common Component Types
Functional Component
A Functional Component is the simplest form of a Preact component. Sometimes called “dumb” component - as it doesn´t have a logic part. It takes optional props and returns JSX.
// without any Props
const FunctionalComponent = () => <div>Function Component</div>;
// with Props
const FunctionalComponent = props => <div>{props.title}</div>;
State Component with Hook
A Stateful Component uses hooks like useState and useEffect to manage local state and side effects in a functional way.
const HookComponent = ({ initialCount = 0 }) => {
const [count, setCount] = useState(initialCount);
useEffect(() => {
console.log(`Count updated: ${count}`);
}, [count]);
return (
<div>
<p>Current count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
};
Signal Component
A Signal Component is a modern reactive approach to manage state and updates. Instead of relying on re-renders triggered by state changes, it automatically updates only the parts of the UI that depend on a specific signal, resulting in highly efficient and predictable rendering behavior.
import { signal, computed, effect } from '@preact/signals';
export const App = () => {
const name = signal('John');
const surname = signal('Doe');
const fullName = computed(() => name.value + ' ' + surname.value);
const count = signal(0);
effect(() => console.log(`count changed to: ${count}`));
return (
<>
<h3>Hello, {fullName}</h3>
<input
class="form-control"
value={name}
onInput={event => (name.value = event.currentTarget.value)}
/>
<input
class="form-control"
value={surname}
onInput={event => (surname.value = event.currentTarget.value)}
/>
<button class="btn btn-primary btn-sm" onClick={() => count.value++}>
click me!
</button>
</>
);
};
Class Component
A Class Component is an older but sill valid approach that manages state and lifecycle methods within a class-based structure.
class ClassComponent extends Component {
state = { count: 0 };
increment = () => {
this.setState(prev => ({ count: prev.count + 1 }));
};
render() {
const { count } = this.state;
return (
<div>
<p>Current count: {count}</p>
<button onClick={this.increment}>+1</button>
</div>
);
}
}
Higher-Order Component
A Higher-Order Component (HOC) is a function that takes a component and returns a new one, enhancing it with additional functionality or styling - like a wrapper.
const withStyle = WrappedComponent => {
return props => (
<div style={{ border: '2px solid black', padding: '8px' }}>
<WrappedComponent {...props} />
</div>
);
};
const SimpleBox = ({ text }) => <div>{text}</div>;
export const BoxWithStyle = withStyle(SimpleBox);
Controlled Component
A Controlled Component keeps its form input values in sync with component state, giving you full control over user input behavior.
const ControlledInput = () => {
const [value, setValue] = useState('');
const handleChange = event => {
setValue(event.target.value);
};
return (
<div>
<label>Your name:</label>
<input type="text" value={value} onInput={handleChange} />
</div>
);
};
Forwarded Ref Component
A Forwarded Ref Components allows you to pass refs through components to access DOM elements or child components directly.
const InputWithRef = forwardRef((props, ref) => <input ref={ref} {...props} />);
Access ref in another component - i.e. set focus on input after clicking on a button
const RefAccessExample = () => {
const inputRef = useRef(null);
const handleFocus = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
return (
<InputWithRef ref={inputRef} />
<button onClick={handleFocus}>focus input</button>
);
};
Portal Component
A Portal Component allows rendering children into a different part of the DOM tree - often used for modals, tooltips or overlays.
Create a simple portal by importing createPortal and assign a DOM target to it.
import { createPortal } from 'preact/compat';
const Portal = ({ children }) => {
return createPortal(children, document.body);
};
Use the Portal Component anywhere with custom content:
const App = () => {
return (
<div>
<p>some text with normal DOM flow</p>
<Potal>
<div style={{ position: 'fixed', top: '20px', right: '20px' }}>
this div is rendered as a portal
</div>
</Portal>
</div>
);
};