Подъём состояния
Когда несколько компонентов должны использовать одни и те же данные, состояние поднимают в их общего родителя. Это называется lifting state up.
Проблема
Два компонента хотят знать одно значение:
function TemperatureInput() {
const [temp, setTemp] = useState(0);
return <input value={temp} onChange={(e) => setTemp(+e.target.value)} />;
}
function TemperatureDisplay() {
// как получить temp?
}
TemperatureDisplay не может прочитать состояние TemperatureInput — оно локальное.
Решение
Состояние поднимается в родителя. Родитель передаёт значение и функцию обновления через пропсы.
function Calculator() {
const [temp, setTemp] = useState(0);
return (
<>
<TemperatureInput value={temp} onChange={setTemp} />
<TemperatureDisplay value={temp} />
</>
);
}
function TemperatureInput({ value, onChange }: {
value: number;
onChange: (v: number) => void;
}) {
return <input value={value} onChange={(e) => onChange(+e.target.value)} />;
}
function TemperatureDisplay({ value }: { value: number }) {
return <p>{value}°C</p>;
}
Односторонний поток
Данные текут вниз через пропсы, события — вверх через функции обратного вызова.
App (state)
├── Child A (props: value)
└── Child B (props: value, onChange)
Пример: корзина
function Shop() {
const [cart, setCart] = useState<CartItem[]>([]);
function addToCart(item: CartItem) {
setCart([...cart, item]);
}
function removeFromCart(id: number) {
setCart(cart.filter((i) => i.id !== id));
}
return (
<>
<ProductList onAdd={addToCart} />
<Cart items={cart} onRemove={removeFromCart} />
<Total items={cart} />
</>
);
}
Один источник истины — cart в Shop. Все остальные компоненты получают данные через пропсы.
Проблема prop drilling
Если компонентов много и состояние нужно глубоко в дереве — пропсы приходится прокидывать через промежуточные компоненты, которые их не используют:
<App user={user}>
<Layout user={user}>
<Sidebar user={user}>
<Profile user={user} />
Layout и Sidebar не используют user, но вынуждены его передавать. Это называется prop drilling.
Решение — контекст (следующий урок).
Когда поднимать
- Данные нужны нескольким компонентам
- Компоненты — соседи или на разных уровнях
- Есть общий родитель, который может хранить состояние
Когда не поднимать
- Данные нужны одному компоненту
- Подъём усложняет код без необходимости
- Состояние нужно очень глубоко — тогда контекст или стор
Итоги
- Подъём состояния — в ближайшего общего родителя
- Данные вниз, события вверх
- Один источник истины
- Prop drilling — проблема, которую решает контекст