useState: какво е това, hook за състояние и синтаксис в React

Автор: IT Sectr Публикувано: 2026-07-04 Време за четене: 9 мин

useState — е вграден React hook, който позволява на функционалните компоненти да управляват локално състояние без преобразуване в класови компоненти. React 16.8 въведе hooks, а useState стана най-използваният сред тях, заменяйки this.state и this.setState от класовия подход. Според React Documentation (2025), повече от 80% от компонентите в съвременните React приложения използват useState за управление на данни от форми, флагове на интерфейса и броячи. Hook-ът връща кортеж от текущата стойност и функция-сетер, която актуализира състоянието и инициира повторно рендериране на компонента.

Основни точки

  • useState — hook за управление на локално състояние във функционални React компоненти.
  • Кортеж — връща двойка [стойност, сетер], където сетер е функцията за актуализиране на състоянието.
  • Повторно рендериране — извикването на сетер винаги инициира прерисуване на компонента с новата стойност.
  • Типове данни — useState работи с числа, низове, масиви, обекти и булеви стойности.
  • Неизменяемост — състоянието не може да се мутира директно, само чрез функцията-сетер.

Какво е useState в React

useState — е основният React hook, добавен във версия 16.8, който дава на функционалните компоненти възможност да съхраняват и променят локално състояние. Преди появата на hooks, състоянието можеше да се използва само в класови компоненти чрез this.state и this.setState, което правеше функционалните компоненти изключително презентационни. useState премахна това ограничение, позволявайки писането на цялото приложение върху функционални компоненти.

Hook-ът приема един аргумент — начална стойност на състоянието — и връща масив от два елемента. Първият елемент е текущата стойност на състоянието, вторият — функция за неговото актуализиране. React гарантира, че функцията-сетер е стабилна и не се променя между рендериранията, което позволява безопасното ѝ предаване на дъщерни компоненти и използване в затваряния.

Според React DevTools Usage Survey (2024), useState се използва в 96% от React приложенията, което го прави най-разпространеният hook в екосистемата. Дори в приложения, използващи глобално състояние чрез Redux или Zustand, локалното състояние чрез useState остава основният механизъм за управление на UI състояние — отворени модали, стойности на полета за въвеждане, активни раздели.

jsx
import { useState } from 'react';

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

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

Как работи useState

Вътрешният механизъм на useState се основава на системата от fiber възли на React. Всеки компонент в React е представен от fiber възел, който съхранява свързания с него списък от hooks под формата на свързан списък. Когато компонентът извика useState, React създава нов възел в този списък и съхранява в него текущата стойност на състоянието и препратка към опашката за актуализации.

При извикване на функцията-сетер, React не актуализира състоянието веднага. Вместо това поставя актуализацията в опашка (pending state queue), планира повторно рендериране на компонента и едва по време на следващото рендериране изчислява новото състояние на базата на старото и приложените актуализации. Това осигурява групиране — ако в един манипулатор на събитие извикате сетер три пъти, React ги групира в едно повторно рендериране.

Според React Team — React 18 Working Group (2024), автоматичното групиране беше разширено в React 18: сега актуализациите на състоянието се групират не само в манипулатори на събития, но и в setTimeout, Promise обратни извиквания и нативни манипулатори. Това доведе до увеличение на производителността до 30% в сценарии с множество актуализации на състоянието.

Функционално актуализиране на състоянието

Когато новото състояние зависи от предишното, използвайте функционалната форма на сетер: setCount(prev => prev + 1). React предава на функцията актуалната стойност на състоянието в момента на прилагане на актуализацията, което гарантира коректност дори при групирани актуализации. Без функционална форма, setCount(count + 1) може да използва остаряла стойност, ако бъде извикано няколко пъти подред.

jsx
// Мързелива инициализация — изпълнява се само веднъж
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Result: count increased by 3

// NOT batch-safe: stale closure
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Result: count increased by 1 (stale closure)

Синтаксис на useState: декларация и актуализация

Основният синтаксис на useState е изключително кратък: const [state, setState] = useState(initialValue). Началната стойност се използва само при първото рендериране; при следващи рендерирания React я игнорира и връща текущата запазена стойност. Ако началното изчисление изисква скъпи операции, предайте функция-инициализатор: useState(() => computeExpensiveInitial()).

Мързеливата инициализация (lazy initial state) е особено важна, когато началната стойност идва от localStorage, сложна трансформация на данни или парсване на URL параметри. React извиква функцията-инициализатор само веднъж — при монтиране на компонента, което спестява ресурси при следващи рендерирания. Без мързелива инициализация, скъпият израз ще се изчислява при всяко рендериране, дори ако резултатът му се игнорира.

ФормаПримерКога да се използва
ДиректнаuseState(0)Проста начална стойност
МързеливаuseState(() => compute())Скъпо начално изчисление
Функционален сетерsetState(prev => prev + 1)Актуализация на базата на предишна
Директен сетерsetState(newValue)Новата стойност не зависи от старата
jsx
// Състояние на обект — създайте нова референция
const [user, setUser] = useState(() => {
    const saved = localStorage.getItem('user');
    return saved ? JSON.parse(saved) : null;
});

useState с различни типове данни

useState работи еднакво добре с примитиви (числа, низове, булеви) и референтни типове (масиви, обекти). Има обаче важна разлика: за примитивите React открива промяната по стойност, за обектите и масивите — по референция. Мутация на съществуващ обект без създаване на нов няма да предизвика повторно рендериране, тъй като референцията е останала същата.

При работа с обекти и масиви винаги създавайте ново копие с променените данни. За обекти използвайте spread синтаксис: setUser(prev => ({...prev, name: newName})). За масиви — методи, които връщат нов масив: filter, map, concat, или spread синтаксис за добавяне на елементи. Мутационните методи като push, pop, splice директно няма да работят — React ще ги игнорира, тъй като референцията към масива не се е променила.

jsx
// ✅ Правилно: hooks на най-високо ниво
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) =>
    setForm(prev => ({ ...prev, [field]: value }));

// ...
const [items, setItems] = useState([]);
const addItem = item =>
    setItems(prev => [item, ...prev]);

Правила за използване на hooks с useState

Както всички React hooks, useState се подчинява на две правила. Първо: извиквайте hooks само на най-високото ниво на компонента — не могат да се поставят вътре в условия, цикли или вложени функции. Това гарантира, че hooks се извикват в същия ред при всяко рендериране, което е критично за вътрешния свързан списък на React.

Второ правило: извиквайте hooks само от функционални React компоненти или персонализирани hooks. Не извиквайте useState от обикновени функции, обратни извиквания или класови компоненти. Нарушаването на тези правила води до грешка Invalid hook call, която React улавя по време на изпълнение.

  • Не в условия — if (flag) { useState(0) } нарушава реда на извикване на hooks.
  • Не в цикли — for (...) { useState(0) } прави реда непредвидим.
  • Не в обратни извиквания — useEffect(() => { useState(0) }, []) ще развали свързания списък.
jsx
// ❌ Проблем с остаряло затваряне
function GoodComponent() {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('');
    // ✅ Поправено с функционална актуализация
}

// броячът е остарял!
function BadComponent() {
    if (isLogged) {
        const [user, setUser] = useState(null);
    }
}

Типични грешки с useState

Най-честата грешка — директна мутация на обекти и масиви вместо създаване на нови референции. Програмистите са свикнали с мутабилния стил от класовите компоненти, където this.state.user.name = „Ново име“ работеше (въпреки че не беше препоръчително). Във функционалните компоненти такава мутация просто се игнорира: React не вижда промяна на референцията и не прерисува компонента.

  • Мутация на обект — user.name = „Ново“ вместо setUser({...user, name: „Ново“}).
  • Остаряло затваряне — използване на остаряла стойност в сетер без функционална форма.
  • Излишни повторни рендерирания — извикване на сетер със същата стойност (React 18 все пак ще рендерира за примитиви).
  • Нулиране на състояние — неволно актуализиране на key проп на компонента, което го монтира отново.

Проблемът с остаряло затваряне (stale closure) възниква, когато обратно извикване, предадено на useEffect или манипулатор на събитие, „улавя” остаряла стойност на състоянието от затварянето в момента на създаване на обратното извикване. Решението — използване на функционалната форма на сетера или включване на необходимите стойности в масива от зависимости на useEffect. Според React Documentation — Hooks FAQ (2025), остарелите затваряния са втората най-честа причина за грешки в hooks след неправилния масив от зависимости.

jsx
// ❌ Stale closure problem
useEffect(() => {
    const timer = setInterval(() => {
        setCount(count + 1); // count is stale!
    }, 1000);
    return () => clearInterval(timer);
}, []);

// ✅ Fixed with functional update
useEffect(() => {
    const timer = setInterval(() => {
        setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(timer);
}, []);

Често задавани въпроси

Може ли useState да се използва за сложни вложени обекти?

Да, но с внимание. За дълбоко вложени обекти всяко ниво изисква копиране при актуализация: setState(prev => ({...prev, nested: {...prev.nested, key: newValue}})). Ако имате обекти с три или повече нива на влагане, обмислете Immer (библиотека за неизменяема актуализация) или разделете състоянието на няколко useState за различни нива.

useState — асинхронен или синхронен е?

useState е асинхронен в смисъл, че извикването на сетер не актуализира стойността веднага. React поставя актуализацията в опашка и я изпълнява при следващото рендериране. След setCount(newValue) променливата count в текущата функция все още съдържа старата стойност. Новата стойност ще бъде достъпна едва при следващото извикване на компонента. Механизмът на групиране гарантира, че множеството извиквания са групирани в едно рендериране.

Какво ще се случи, ако useState се извика извън компонента?

React ще хвърли грешка Invalid hook call. Hooks могат да се извикват само вътре във функционални React компоненти или персонализирани hooks (функции, чието име започва с use). Това ограничение е вградено в имплементацията на hooks: те използват fiber дървото на компонента за съхранение на състояние, а извън компонента това дърво не е достъпно.

Кога да използваме useState и кога useReducer?

useState е подходящ за прости независими състояния (броячи, полета за въвеждане, флагове). useReducer е по-добър, когато състоянието е сложен обект с множество полета, логиката на актуализация зависи от типа действие или следващото състояние изисква сложна трансформация. Практическо правило: ако имате повече от три взаимосвързани полета на състоянието — използвайте useReducer.

Защо useState не актуализира стойността веднага?

Това е направено за производителност. Ако useState актуализираше състоянието синхронно, всяко извикване на сетер би причинило незабавно повторно рендериране, което би довело до множество прерисувания в рамките на един манипулатор на събитие. Групирането, при което React групира актуализациите и изпълнява едно повторно рендериране, е оптимизация, въведена още в React 16 и значително подобрена в React 18 с автоматично групиране.

Резюме

  • useState — основният React hook за управление на локално състояние във функционални компоненти, връщащ [state, setter].
  • Неизменяемост — състоянието не може да се мутира директно; винаги предавайте нова стойност или използвайте функционалната форма на сетера.
  • Мързелива инициализация — за скъпи начални изчисления предайте функция: useState(() => compute()).
  • Функционален сетер — setState(prev => prev + 1) гарантира коректност при групирани актуализации.
  • Групиране — React групира множество извиквания на сетер в едно повторно рендериране за оптимизация.
  • Правила за hooks — извиквайте useState само на най-високото ниво на компонента, не в условия или цикли.
  • Типове данни — за обекти и масиви винаги създавайте нова референция при актуализация.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също