Сейчас боле менее складывается понимание (не буду придераться к используемым терминам, это не особо важно). Но ты слишком все усложняешь. Зачем тебе думать является ли setTimeout частью движка JavaScript или это часть Web API? Зачем тебе думать что попадает в стек, а что нет? Конечно же это хорошо, когда ты понимаешь, но в большинстве случаев это не надо вообще. Даже я не уверен, что понимаю что такое стек, и что вообще об этом когда-нибудь задумываюсь. До того, как начал изучать Си, я вообще о нем не думал. Надо сильно упрощать все до уровня Есть или Нету. setTimeout отработал? Отработал. Значит он есть. useState отработала? Отработала. Значит она есть. Что тебе еще надо? Зачем тебе вот это чего частью оно является или нет? Не усложняй. >> Здесь тоже мне не свосем понятно, когда функция useState попадает в стек при вызове, как сейчас или при инициализации она сразу попадает в стек и жет своего выполнения? А что здесь не ясно? Ты же сам пишешь: "Инициализируем функцию setState". Вот как только инициировали, все, она есть. Доказательство тому - успешный вывод в любом месте за ее объявлением. К слову, Инициализация в данном случае - неправильное употребление. Инициализация - это объявление переменной сразу с задаваемым значением. А в данном случае у нас объявление функции. Функция сама по себе значения не имеет. И если переменную объявлять, но не задавать ей сразу значение, а присваивать значение позднее (пусть даже на следующей строчке), то это отдельно объявление, и позже присвоение. Здесь уже инициализации не будет. Начитался я тут всякого в книге по Си. Вот там это важно, там разное поведение в момент компиляции программы. А здесь нам это не нужно. Но на всякий случай уточнил. Так вот, про объявление функции: еще раз: когда объявили, тогда она и есть. Но объявить - это не вызвать ее. То есть она не работает, ничего не читает и никаких значений не инициирует, пока ее не вызовут. Даже указав в аргументе значение по умолчанию, это значение будет или не будет использовано тогда, когда функция будет вызвана, а не когда функция объявлялась. И так будет каждый раз при вызове, в зависимости от того, какие параметры в нее передавались. При этом, когда мы вызываем функцию, у нас функция не висит, а выполняется, и возвращается ее результат. Поэтому формулировка "где наша функция setState со своим setTimeout...?" вообще не правильная. Наша функция ровно там, где она и была - где мы ее объявили. И далее там, где она видна, то есть находится она в области видимости или нет. Опять-таки, в нашем примере практически все в одной области видимости (кроме того, что выполняется внутри функций). И обе наши функции объявлены в той же области видимости, что и все остальное происходит. Иначе бы у нас попытка обратиться к функции, недоступной в нашей области видимости, просто приводила бы к ошибке. Но у нас же не возникает ошибок, верно? >> Откуда при инициализации функции setState появился count со значением undefined (откуда он вообще count этот берется) А где в моем примере вообще связь с setState и count? И где ты вообще увидил, чтобы хоть в одном месте у меня count был undefined? Но если ты вдруг решил поиграться и в setState в тело функции попытаться обратиться к count и получил undefined, то совсем не удивительно. Ведь count инициируется ниже по коду. var count = useState(5); Что здесь не ясно? А useState сама по себе не возвращает значение count. Она возвращает значение state.field || defaultValue. Где ты в теле этой функции видишь count? Ткни пальцем.

Учимся понимать машину и асинхронно взрываем себе мозг :) Итак, в бар входит в ковбой и требует выпивку - это объявление, декларация намерений. Бармен спрашивает - чем будешь платить: деньгами, отдашь пистолет или отработаешь мытьем посуды? - Я заплачу, - отвечает ковбой, - у меня есть деньги. - Это определение типа данных. Тогда плати 5 баксов и получай выпивку - Ковбой платит и веселье начинается - Это инициализация, присвоение начального значения, запуск процесса в работу. Шаг 1. Инициализируем переменую state со значением undefined. Машина сохраняет ее в памяти со значением undefined. Шаг 2. Инициализируем функцию useState в аргуаментах ждем парметр defaultValue с условием, если state === undefined присвой state пустой обьект в который положи ключ field со значением defaultValue. Машина видит, что мы инициализировали функцию useState со значением state = undefined. Шаг 3. Инициализируем функцию setState в аргуаментах ждем парметр value в теле функции вызываем функцию setTimeout, которой в объект state записываем значение ключ field со значением value. Данная функция отправляется в стек, но так как внутри функции setState, находится функция setTimeout, которая не является частью JavaScript движка, а является Web API браузера как дополнительный функционал она отправляется в Web API. Далее Web API браузера запускает таймер в 2000ms, оставляя на фоне setTimeout(). Шаг 4. Следующая строка в нашем скрипте это console.log("state", state); , отправленное в стек и выкинутое оттуда после выполнения. Это получается наш первый выкинутый в консоль результат в данный момент наш state = undefined, поэтому получаем: 1. "state" undefined Шаг 5. Инициализируем переменую count и делаем вызов функции useState(со значением 5) и присваеваем результат перемной count. В аргументе defaultValue функция useState теперь хранится значение 5. Теперь в функции у нас идет проверка условий if(state === undefined), так как state у нас по прежнему undefined условие true, поэтому оно выполняется дальше создаем пустой объект state = {};, переходим к следуещему условию создаем в объекте ключ field со значением defaultValue получается field: 5, так как мы вызвали функцию useState и положили в defaultValue = 5. Теперь return нам возвращает Return value 5. Здесь тоже мне не свосем понятно, когда функция useState попадает в стек при вызове, как сейчас или при инициализации она сразу попадает в стек и жет своего выполнения? Шаг 6. Следующая строка в нашем скрипте это console.log("count 1", count); , отправляется в стек и выкидывается оттуда после выполнения. В результате мы получаем наш второй вывод в консоль. 2. "count 1" 5 На этом месте все, я уже ничего не понимаю на самом деле, что происходит. Во-первых где наша функция setState со своим setTimeout она здесь вообще в процесе участвует или мы про нее вообще забыли? Откуда при инициализации функции setState появился count со значением undefined (откуда он вообще count этот берется)? В этом шаге мы получаем в консоль лог count из инициализированной переменой var count = useState(5); или он к нам все-таки прилетает из функции setState?

Кодепен не выводит их одновременно. Это же две разных строчки, то есть два отдельных вывода. Просто пауза между ними минимальная, так как в ответ на изменение стейта происходит сразу ререндеринг, и это срабатывает без твоего участия, то есть не приходится кликать кнопку для этого. У тебя там сейчас отработало все так, как и должно было отработать. Если ты не понимаешь почему так происходит, а главное - пытаешься заставить код выполнять так, как ты этого хочешь, то займись корректировкой своего мышления. Ошибка многих начинающих в том, что они пытаются научиться магии, думая, что программировать - это заставлять машину делать то, что мы хотим. Это неправильно. Научиться программировать - это научиться понимать машину и понимать что произойдет, если сдеть то или иное, и главное - научиться понимать машину, почему происходит так, как происходит, а не так, как мы этого ожидали (то есть научиться фиксить баги в себе, а не в коде). Сейчас твоя проблема все еще в том, что ты неправильно понимаешь выполнение useState. Пойми: useState всегда именно возвращает, а не устанавливает значение. Ты думаешь так: в первый раз она установит и потом вернет значение из стейта, а потом она будет сразу возвращать из стейта. Это неправильное восприятие. Хотя конечно же по сути именно так и происходит, но все же правильно понимать так: она сразу же вернет или значение из стейта (если оно есть), или значение, переданное по умолчанию (и присвоит это значение стейту, но так, что это не вызывает ререндеринга). Для того, чтобы это понять, посмотри вот этот код: Выполни его в консоли браузера и попробуй оценить результат. А результат будет таков: Обравти внимание, что state = undefined только в первый раз. Затем у нас всегда один и тот же объект стейта, только меняется его свойство. В setState я прописал вызов через setTimeout, которое и позволяет симитировать работу нативного setState в том плане, что мы не получаем сразу измененного объекта стейта, то есть код далее выполняется все еще со старым значением стейта. А второй setTimeout с двухсекундной задержкой имитирует повторный ререндеринг, в котором уже новое значение стейта, то есть хотя мы и не вызываем в этом блоке setState, а получаем актуальное значение через useState, мы получаем именно новое значение. При этом я специально здесь сразу два вывода count сделал, чтобы показать тебе, что старая переменная count даже через 2 секунды содержала именно старое значение, после чего мы ей присвоили новое значение. Вот научись понимать эту логику и то, что код рендерера каждый раз выполняется от и до.

Олег, неправильно делаешь (просто картинку прислал). Делай клон кодепен-проекта и присылай ссылку.

Вообщем попытаюсь прям по микрочастям все раложить, чтобы разобраться.

Если бы ты смог немного переписать свой пример под этот сервис Нет, не буду. Это получится медвежья услуга. Ведь нельзя просто так переписать с сохранением функционала реакта. Мы ведь в реакте пишем мало, а под капотом происходит много. Поэтому мне придется, во-первых, написать больше кода (а тогда и материала для изучения у тебя возникнет больше, и сложнее будет освоить). Во-вторых, ты не сможешь мыслить в стиле реакта. Тебе надо осваивать именно в реакте, чтобы мыслить в реакте, потому что там другая парадигма. Так что осваивай то, что есть. А вообще, тебе наверно поможет лучшее освоение классовых компонентов, потому что очевидно, что ты не понимаешь, что есть объект стейта (в классах он через this.state), и что при выполнении setState() происходит обновление этого объекта. И что такое поведение функций называется "Побочный эффект", когда функция вызывается не для того, чтобы что-то вернуть, а чтобы что-то изменить.

Вот сейчас появилась идея обвешать весь твой код console.log, может будет более понятно, сейчас попробую.

Я не затягиваю мне нужно его доделать там немного осталось, чтобы переносить готовое решение. Плюс ты мне мозг взорвал асинхроностью, вчера весь день изучал асинхроность, промисы, замыкание, контекст и.тд., но пока так и непонял, как работает твой пример. Нашел вот такой сервис, который демнострирует, как работает event loop http://latentflip.com/loupe/ , примерно понятно, но твой пример не получается там посмотреть, там редактор немного по другому работает, чем на codepen.io в return ругается на кнопку ее нужно в html выносить, а как ее вернуть там не понимаю. Если бы ты смог немного переписать свой пример под этот сервис было бы очень круто, потому-что сейчас сцуко не получается понять, как все-таки работает твой пример.

Олег, ты давай не затягивай с переходом на новый движок. Я хочу кое-какие полезные наработки выкатить (хуки), но пока ты не понимаешь TS и прочие базовые вещи, это не имеет смысла.