← Усі теми

Питання на співбесіді з керування станом з відповідями

useState і useReducer, prop drilling, Context, Redux Toolkit, Zustand, а також серверний стан: TanStack Query, RTK Query, SWR і loader/action у React Router.

225 запитань для співбесіди з теми Керування станом з відповідями й поясненнями - рівні Junior, Middle і Senior. Приклади запитань, онлайн-тести й задачі на код.

Запитання за рівнями

Приклади запитань

Кілька запитань із кожного рівня з правильною відповіддю й поясненням.

Керування станом · Junior

  1. Що таке «стан» (state) у React-компоненті?

    Правильна відповідь: Дані, які змінюються з часом і впливають на екран; зміна спричиняє ререндер

    Стан - це пам'ять компонента між рендерами: значення лічильника, текст у полі, чи відкрите меню. Звичайна змінна let скидається при кожному рендері, і її зміна не просить React оновити UI. Пропси - вхідні дані лише для читання, ними володіє батько.

  2. Коли потрібна функціональна форма setCount(c => c + 1) замість setCount(count + 1)?

    Правильна відповідь: Коли нове значення залежить від попереднього, особливо за кількох оновлень поспіль

    count - знімок поточного рендера. Три виклики setCount(count + 1) в одному обробнику дають +1, а три setCount(c => c + 1) - +3: кожен апдейтер отримує результат попереднього. Це ж захищає від застарілих замикань у таймерах і ефектах.

  3. Як видалити елемент з id з масиву в стані?

    Правильна відповідь: setItems(items.filter(i => i.id !== id))

    Стан оновлюють іммутабельно: filter, map, spread і toSorted створюють новий масив. splice і delete мутують наявний, посилання не змінюється, і React пропускає оновлення.

  4. Навіщо передавати функцію в useState(() => createInitialTodos())?

    Правильна відповідь: Щоб дороге обчислення виконалося лише на першому рендері

    useState(createInitialTodos()) викликає функцію на кожному рендері, хоча результат потрібен один раз. Лінивий ініціалізатор useState(createInitialTodos) викликається лише під час монтування. Він має бути синхронним і чистим.

Усі 75 запитань з відповідями →

Керування станом · Middle

  1. Як скинути стан компонента форми під час зміни вибраного користувача?

    Правильна відповідь: Рендерити його з key={userId}, щоб React перестворив компонент

    Інший key змушує React вважати це новим компонентом: старий стан відкидається, застосовуються початкові значення. Ефект для скидання спершу рендерить застарілі дані, а потім виправляє їх - зайвий рендер і помітне блимання.

  2. Як передати dispatch з useReducer глибоко в дерево без prop drilling?

    Правильна відповідь: Покласти dispatch в окремий контекст; він не змінюється, і споживачі не перемальовуються

    Патерн «редʼюсер + контекст»: один контекст для state, інший - для dispatch. Компоненти, які лише надсилають дії (кнопки, форми), читають стабільний контекст з dispatch і не перемальовуються при зміні стану.

  3. Навіщо потрібен третій аргумент init у useReducer(reducer, arg, init)?

    Правильна відповідь: Лінива ініціалізація: init(arg) викликається лише на першому рендері

    useReducer(reducer, username, createInitialState) уникає перерахунку дорогого початкового стану на кожному рендері - як лінивий ініціалізатор у useState. init можна перевикористати й для скидання стану.

  4. Компонент використовує лише theme з великого AppContext, але перемальовується при кожній зміні кошика. Що допоможе?

    Правильна відповідь: Розділити контекст на менші за доменом і частотою змін

    React.memo не зупиняє ререндери через контекст, який читає компонент. Окремі ThemeContext і CartContext обмежують оновлення потрібними споживачами. Для дуже частих оновлень - стор із селекторами.

Усі 75 запитань з відповідями →

Керування станом · Senior

  1. Чому Redux, Zustand і схожі бібліотеки підписуються через useSyncExternalStore?

    Правильна відповідь: Він гарантує узгоджений знімок під час конкурентного рендерингу (без tearing)

    Під час конкурентного рендерингу React може призупинити рендер; якщо зовнішній стор у цей час зміниться, одні компоненти прочитають старе значення, інші - нове. useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) запобігає цьому й підтримує SSR.

  2. У чому різниця між моделлю «підписка на селектор» (Redux, Zustand) і Context?

    Правильна відповідь: Стор сповіщає компоненти, і кожен перемальовується, лише якщо змінилася вибрана ним частина

    У Context немає селекторів: будь-яка зміна value перемальовує всіх споживачів. Стори виконують селектор кожного підписника й порівнюють результати, тому оновлення точкові. Бібліотеки на кшталт use-context-selector емулюють це поверх Context.

  3. Де в застосунку з роутингом найкраще зберігати стан фільтра списку (пошук, сортування, сторінка)?

    Правильна відповідь: У search-параметрах URL - посиланням можна поділитися, стан переживає перезавантаження й працює з «назад/вперед»

    URL - теж стан. Фільтри в ?q=&sort=&page= роблять посилання зручними для поширення, а історію - осмисленою; loader'и й ключі запитів можуть виводитися з них. Введення тексту дебаунсять і замінюють (а не додають) записи історії на кожне натискання.

  4. Яка класифікація стану допомагає вибирати інструменти у великому застосунку?

    Правильна відповідь: Серверний кеш, стан URL, стан форм, локальний UI-стан і глобальний клієнтський стан

    Кожен вид має природне місце: серверний кеш - TanStack Query/RTK Query/SWR/loader'и; URL - роутер; форми - локальний стан чи бібліотека форм; UI - useState; справді глобальний клієнтський стан - Context або стор. Якщо складати все в один стор, він стає вузьким місцем.

Усі 75 запитань з відповідями →

Збірні тести з цією темою

Запитання з кількох тем одразу - як на співбесіді на конкретну вакансію.

Задачі на код

Напишіть рішення просто в браузері - тести перевірять його одразу. Класика співбесід: debounce, throttle, deepClone, Promise.all, EventEmitter, LRU-кеш та інші.

Відкрити задачі →