useState — это хук, который позволяет функциональным
компонентам хранить и изменять внутреннее состояние. В отличие от
классовых компонентов, где состояние определяется через
this.state и изменяется с помощью
this.setState, функциональные компоненты с
useState становятся полноценными носителями состояния без
необходимости создания классов.
import { h } from 'preact';
import { useState } from 'preact/hooks';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Счетчик: {count}</p>
<button onCl ick={() => setCount(count + 1)}>Увеличить</button>
</div>
);
}
В этом примере:
count — текущее значение состояния.setCount — функция для его изменения.useState(0) — инициализация состояния значением
0.useState всегда возвращает массив из двух элементов:
const [state, setState] = useState(initialValue);
Если передать функцию в setState, она будет вызвана с
текущим значением состояния:
setCount(prevCount => prevCount + 1);
Это важно для правильного обновления состояния при множественных вызовах в одном рендере.
useState позволяет задавать начальное
значение различными способами:
const [text, setText] = useState('Привет');
const [value, setValue] = useState(() => expensiveComputation());
Ленивая инициализация используется, когда начальное значение требует сложных вычислений. Функция вызывается только при первом рендере.
Состояние в Preact обновляется асинхронно и вызывает повторный рендер компонента. Прямое присвоение переменной не влияет на рендер:
let count = 0;
count += 1; // рендер не обновится
Только вызов setCount уведомляет Preact о необходимости
обновить компонент:
setCount(count + 1);
Можно передавать функцию для вычисления нового значения на основе предыдущего:
setCount(prev => prev + 1);
Это гарантирует корректное обновление при нескольких последовательных вызовах.
Часто состояние представляет собой сложные структуры: массивы, объекты. При этом необходимо создавать новые объекты, а не изменять существующие:
const [items, setItems] = useState([]);
function addItem(item) {
setItems(prevItems => [...prevItems, item]);
}
Для объектов:
const [user, setUser] = useState({ name: 'Иван', age: 30 });
function updateAge(newAge) {
setUser(prevUser => ({ ...prevUser, age: newAge }));
}
Прямое изменение объекта, например user.age = 31, не
вызовет рендер компонента.
В Preact можно использовать несколько независимых состояний в одном компоненте:
const [count, setCount] = useState(0);
const [text, setText] = useState('');
Каждое состояние управляется отдельно и может обновляться независимо, что упрощает логику компонентов.
useState привязан к конкретному порядку вызовов хуков.useState внутри компонента приведет к некорректному
поведению.useEffect и колбэках без дополнительных зависимостей.import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <div>Прошло секунд: {seconds}</div>;
}
function Form() {
const [formData, setFormData] = useState({ name: '', email: '' });
const handleChange = e => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
return (
<form>
<input name="name" value={formData.name} onIn put={handleChange} />
<input name="email" value={formData.email} onIn put={handleChange} />
</form>
);
}
useStatesetState вызывают повторный
рендер.useState является фундаментальным инструментом для
создания интерактивных компонентов в Preact, позволяя функциональным
компонентам вести себя так же динамично, как классовые с
this.state.