Питання на співбесіді з керування станом з відповідями
useState і useReducer, prop drilling, Context, Redux Toolkit, Zustand, а також серверний стан: TanStack Query, RTK Query, SWR і loader/action у React Router.
225 запитань для співбесіди з теми Керування станом з відповідями й поясненнями - рівні Junior, Middle і Senior. Приклади запитань, онлайн-тести й задачі на код.
- useState
- useReducer
- Context
- Redux Toolkit
- Zustand
- TanStack Query
- RTK Query
- SWR
- React Router
Запитання за рівнями
Junior
Базові поняття та синтаксис · 50 запитань
Middle
Практика, нюанси й оптимізація · 50 запитань
Senior
Архітектура, внутрішня будова, edge cases · 50 запитань
Приклади запитань
Кілька запитань із кожного рівня з правильною відповіддю й поясненням.
Керування станом · Junior
- Що таке «стан» (state) у React-компоненті?
Правильна відповідь: Дані, які змінюються з часом і впливають на екран; зміна спричиняє ререндер
Стан - це пам'ять компонента між рендерами: значення лічильника, текст у полі, чи відкрите меню. Звичайна змінна
letскидається при кожному рендері, і її зміна не просить React оновити UI. Пропси - вхідні дані лише для читання, ними володіє батько. - Коли потрібна функціональна форма
setCount(c => c + 1)замістьsetCount(count + 1)?Правильна відповідь: Коли нове значення залежить від попереднього, особливо за кількох оновлень поспіль
count- знімок поточного рендера. Три викликиsetCount(count + 1)в одному обробнику дають +1, а триsetCount(c => c + 1)- +3: кожен апдейтер отримує результат попереднього. Це ж захищає від застарілих замикань у таймерах і ефектах. - Як видалити елемент з
idз масиву в стані?Правильна відповідь:
setItems(items.filter(i => i.id !== id))Стан оновлюють іммутабельно:
filter,map, spread іtoSortedстворюють новий масив.spliceіdeleteмутують наявний, посилання не змінюється, і React пропускає оновлення. - Навіщо передавати функцію в
useState(() => createInitialTodos())?Правильна відповідь: Щоб дороге обчислення виконалося лише на першому рендері
useState(createInitialTodos())викликає функцію на кожному рендері, хоча результат потрібен один раз. Лінивий ініціалізаторuseState(createInitialTodos)викликається лише під час монтування. Він має бути синхронним і чистим.
Керування станом · Middle
- Як скинути стан компонента форми під час зміни вибраного користувача?
Правильна відповідь: Рендерити його з
key={userId}, щоб React перестворив компонентІнший
keyзмушує React вважати це новим компонентом: старий стан відкидається, застосовуються початкові значення. Ефект для скидання спершу рендерить застарілі дані, а потім виправляє їх - зайвий рендер і помітне блимання. - Як передати
dispatchзuseReducerглибоко в дерево без prop drilling?Правильна відповідь: Покласти
dispatchв окремий контекст; він не змінюється, і споживачі не перемальовуютьсяПатерн «редʼюсер + контекст»: один контекст для
state, інший - дляdispatch. Компоненти, які лише надсилають дії (кнопки, форми), читають стабільний контекст з dispatch і не перемальовуються при зміні стану. - Навіщо потрібен третій аргумент
initуuseReducer(reducer, arg, init)?Правильна відповідь: Лінива ініціалізація:
init(arg)викликається лише на першому рендеріuseReducer(reducer, username, createInitialState)уникає перерахунку дорогого початкового стану на кожному рендері - як лінивий ініціалізатор уuseState.initможна перевикористати й для скидання стану. - Компонент використовує лише
themeз великогоAppContext, але перемальовується при кожній зміні кошика. Що допоможе?Правильна відповідь: Розділити контекст на менші за доменом і частотою змін
React.memoне зупиняє ререндери через контекст, який читає компонент. ОкреміThemeContextіCartContextобмежують оновлення потрібними споживачами. Для дуже частих оновлень - стор із селекторами.
Керування станом · Senior
- Чому Redux, Zustand і схожі бібліотеки підписуються через
useSyncExternalStore?Правильна відповідь: Він гарантує узгоджений знімок під час конкурентного рендерингу (без tearing)
Під час конкурентного рендерингу React може призупинити рендер; якщо зовнішній стор у цей час зміниться, одні компоненти прочитають старе значення, інші - нове.
useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)запобігає цьому й підтримує SSR. - У чому різниця між моделлю «підписка на селектор» (Redux, Zustand) і Context?
Правильна відповідь: Стор сповіщає компоненти, і кожен перемальовується, лише якщо змінилася вибрана ним частина
У Context немає селекторів: будь-яка зміна
valueперемальовує всіх споживачів. Стори виконують селектор кожного підписника й порівнюють результати, тому оновлення точкові. Бібліотеки на кшталтuse-context-selectorемулюють це поверх Context. - Де в застосунку з роутингом найкраще зберігати стан фільтра списку (пошук, сортування, сторінка)?
Правильна відповідь: У search-параметрах URL - посиланням можна поділитися, стан переживає перезавантаження й працює з «назад/вперед»
URL - теж стан. Фільтри в
?q=&sort=&page=роблять посилання зручними для поширення, а історію - осмисленою; loader'и й ключі запитів можуть виводитися з них. Введення тексту дебаунсять і замінюють (а не додають) записи історії на кожне натискання. - Яка класифікація стану допомагає вибирати інструменти у великому застосунку?
Правильна відповідь: Серверний кеш, стан URL, стан форм, локальний UI-стан і глобальний клієнтський стан
Кожен вид має природне місце: серверний кеш - TanStack Query/RTK Query/SWR/loader'и; URL - роутер; форми - локальний стан чи бібліотека форм; UI -
useState; справді глобальний клієнтський стан - Context або стор. Якщо складати все в один стор, він стає вузьким місцем.
Збірні тести з цією темою
Запитання з кількох тем одразу - як на співбесіді на конкретну вакансію.
Задачі на код
Напишіть рішення просто в браузері - тести перевірять його одразу. Класика співбесід: debounce, throttle, deepClone, Promise.all, EventEmitter, LRU-кеш та інші.
Відкрити задачі →