У світі веб-розробки, особливо у роботі з React, часто виникають ситуації, коли механізми оновлення стану не працюють так, як очікувалося. Одна з таких проблем виникає при використанні хуків useState та useEffect в React. Давайте розглянемо конкретний випадок, коли стан не оновлюється відповідно до очікувань у функціональному компоненті.
Уявімо, що ми маємо React хук з ім’ям useWidgets:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const useWidgets = () => { const [skip, setSkip] = useState(0); const take = 20; async function getItems() { try { console.log('skip завжди дорівнює 0 тут', skip); const rsp = await apiGetWidgets({ skip }); setSkip((state) => state + take); } catch (err) { console.log(err); } } useEffect(() => { getItems(); }, []); return { getItems, skip }; }; |
Також у нас є функціональний компонент Infinite, який використовує цей хук:
1 2 3 4 5 6 7 8 9 10 |
const Infinite: FC = () => { const { getItems, skip } = useWidgets(); useEffect(() => { setTimeout(getItems, 4000) }, []); console.log('skip оновлюється тут до останнього значення', skip); return <div> {skip} </div>; }; |
Проблема полягає в тому, що коли skip оновлюється за допомогою setSkip, зміна значення відображається в функціональному компоненті Infinite, але ця зміна не відображається в хуці useWidgets. skip завжди дорівнює нулю, навіть після оновлення.
Чому так відбувається? Пояснення полягає в тому, що хук useState у React закритий над початковим значенням skip, яке починається з нуля. Тому кожен новий виклик хука useWidgets створює новий екземпляр skip зі значенням за замовчуванням (нуль), навіть після оновлення значення в компоненті Infinite.
Отже, хоча функціональний компонент Infinite може отримати доступ до оновленого значення skip через props, хук useWidgets не може автоматично отримати оновлене значення, оскільки він залишається незалежним екземпляром зі значенням за замовчуванням.