Олег, во-первых, хорошо бы выложить проект на гитхаб (тем более, что он учебный), чтобы проще было разбираться.
Кстати, если добавить здесь именно проект (пока правда только через старый сайт https://old.prisma-cms.com/projects/create ). Так вот, если добавить проект, в нем можно указать ссылку на репозиторий, и в нем же создавать задачки с просьбой о помощи, так же расписав что и как. Такой формат более удачный. Как мне видится.
Но это так, к слову.
По теме: ты совсем запутался и неправильно воспринимаешь происходящее, и неправильно называешь явления.
> Примерно понял из уроков, что если после const поставить console.log('####: usePokemons', pokemons); для примера для хука useState он показывает, что передаю пустой объект
После const ты вообще не можешь поставить console.log (а правильней говорить не ставить, а писать). В данном случае пишешь не после const, а на следующей строке, и не за const, а за const [pokemons, setPokemons] = useState({}); И чтобы понимать что происходи дальше и вообще, тебе надо разобраться что происходит именно здесь, то есть в const [pokemons, setPokemons] = useState({});. И важно здесь понимать синхронное выполнение кода происходит или асинхронное? Потому что от этого зависит будет ли заблокировано дальнейшее выполнение кода пока не выполнится useState({}) или не будет.
Читай очень внимательно про синхронный и асинхронный javascript: https://developer.mozilla.org/ru/docs/Learn/JavaScript/Asynchronous/Introducing (включая вложенные ссылки).
Так вот, важно уяснить, что по умолчанию в JS все функции синхронные, то есть выполнение происходит последовательно, то есть результат выполнения функции возвращается только тогда, когда функция выполнится. Но тут есть подводный камень в том плане, что в качестве результата выполнения функции может быть возвращен, к примеру, объект Promise. То есть это хоть и результат выполнения данной функции, но реальный результат будет возвращен позже, к примеру, через вызов .then(...), или, если мы находимся внутри функции, объявленной с ключевым словом async, используем await.
Да, это все очень сложно, и материала не мало, но это важно выучить и понять. Про асинхронность спрашивают на любом собеседовании, и без этого знания, думаю, даже в джуны нигде не возьмут, потому что иначе не сможешь программировать вообще, вот прям как в этом примере не понимаешь, как что и когда выполняется.
Так вот, запомни: setState (в том числе через хук useState, равно как и другие хуки) выполняется асинхронно. Чтобы понять, вот такой пример посмотрим:
Вот смотри, здесь console.log выполняется не только за выполнением useState, но и за двумя блоками условия if.
При чем очевидно, что первое условие if(count === 0) выполнится обязательно при первом же рендеринге компонента, ведь мы в useState указали начальное значение - 0.
По логике, раз условие выполнилось и вызвался setCount(1) еще до выполнения console.log, у нас count уже должен стать 1 и в console.log должно вывестись 1. Но это не так. На самом деле у нас выведется и 0, и 1, как будто console.log вызвалось два раза. Более того, console.log не как будто два раза вызовется, а реально два раза. Почему так? Потому что при каждом изменении входящих свойств props или изменении текущего состояния state, у нас выполняется ререндеринг компонента, то есть вся его логика render выполняется опять от начала и до конца. И что же у нас на самом деле здесь произошло?
1. У нас установилось стейт-значение count = 0
2. У нас выполнилось условие сравнения значения и вызвался метод изменения состояни.
И вот здесь очень важно понимать, что мы только вызвали изменение состояни, но состояние у нас еще не поменялось. Более того, выполнение кода здесь не прервалось, так что мы идем дальше.
3. Второе условие у нас не выполнилось и вызов изменения состояния не произошел.
4. Мы дошли до вывода переменной count в консоль.
И вот здесь важно еще один момент учесть - замыкания. Дело не только в том, что у нас setState асинхронная, но и в том, что переменную count мы получили выше выполнения логики if-setState. При этом эта переменная со своим собственным значением, а не ссылка на какой-нибудь сторонний объект, так что с момента ее инициализации, ее значение не поменяется в течение всей ее жизни. А у нас она инициировалась со значением 0. Вот мы в консоль и получаем 0.
5. Выполнился окончательный рендеринг HTML-разметки.
6. Мы ведь помним, что у нас выполнилось первое условие count === 0 и вызов изменения состояния? Вот. Состояние изменилось и происходит ререндеринг, то есть повторное выполнение всей логики компонента. И вот там у нас уже count объявляется с новым значением - 1. И пошли по кругу от пункта 1.
Второй пункт у нас не выполняется. Третий тоже. К 4 пункту мы пришли без изменений со значением count = 1 и получаем в консоль вывод 1. Опять пункт 6, то есть рендеринг HTML.
В данном случае мы сразу получили 2 рендеринга компонента, потому что сразу же по условию изменили его состояние. Теперь, чтобы счеткик пошел дальше, нам уже надо кликать кнопку, чтобы вызвать обновление стейта. Кликаем раз и получаем новый count = 2 в стейте. Опять проходим 6 этапов и опять у нас условия не выполняются, так что в консоль как есть выводится 2. Кликаем еще раз. Опять все 6 пунктов, только в п 3 у нас срабатывает условие count === 3. Как и в первом рендеринге, у нас выполнение не прерывается и в консоль выводится 3, но у нас изменился стейт и выполняется новый рендеринг с числом 4. На выходе мы получили в консоль все пять выводов 0 1 2 3 4 5.
Покликать можно здесь: https://codepen.io/fi1osof/pen/RwoapyR
Надеюсь ты освоишь данный материал и тебе станет понятней.