Мне пришлось перейти из .Нет бекенд разработки на фронт, поучаствовать в найме, познакомиться со специалистом с реакт навыками гораздо выше моих, признаться ему в этом и спросить где он черпал знания чтобы узнать об этом канале) Так что вам еще повезло 😁
это гигантский труд. Я как то создавал себе анимацию через adobe after effects. Это ад. Там еще нужно иметь супер мега железо, чтобы не зависло.. А процесс создания инфографики очень долгий. Я думаю на анимацию уходит несколько раз больше времени чем на контент
я честно говоря даже и не знаю, на что уходит больше времени. Очень много занимает расписывание сценария для видео. В плане на такой-то фразе показать вот этот текст или вот на бумаге нарисовал примерный вид страницы. Вот этот подробный видео сценарий занимает очень много
Добро пожаловать!) ну уже как минимум на канале разобраные: useRef, useMemo, коснулись useEffect + useLayoutEffect и новый выпуск во вторник еще раскроет, что-то новое)
спасибо за комментарий! Я в данный момент намеренно не касался этих примеров, т.к. в следующих выпусках планирую про это поговорить более углубленно :)
@@it-sin9k Супер. Рад что покрывашь эти темы :) Кстати сколько времени уходит что бы смонтировать видео? Картинка получается супер, просто интересно почему в итоге допустим не выбрал обычный вариант например как делает Kent C. Dodds, который как мне кажется занимал бы меньше времени.
нас двое, я придумываю контент, записываю аудио и делаю текстовый драфт по визуализации и есть еще товарищ, который делает всю работу по видео ряду, рисует персонажей, делает разные визуальные эффекты и прочее. Поэтому сумарно это занимает очень много времени, посчитать особо не могу. Лишь один контент осознать и продумать подачу у меня занимает пару дней, по факту это как статью придумать и написать. Синяк - это единственный формат контента, который я бы сам стал смотреть. 5 - 10 минут, осознанного текста, с минимизированным количеством лишней информации (скрыт лишний код, лишние контролы в браузере и многое другое), с крупными шрифтами, чтобы смотреть на телефоне было удобно + фокус кода, чтобы понимать о чем речь идет, да и визуализация идеи какого либо патерна сильно упрощает его понимание, это то что смотрел бы я сам. В подаче Kent C. Dodds такого нет, тогда уж лучше по мне прочесть статьи какие-нибудь, чем смотреть длинные ролики с говорящей головй и перегруженным экраном. А я люблю все таки видео формат, поэтому и решил сделать, то что сам бы смотрел.
Забыл одну важную деталь. Что бы этот трюк с useCallback работал, нужно чтобы дочерний компонент был оптимизирован от лишних ререндеров. Например, в родитель прилетает новый пропс, это тригерит ререндер родителя и всего поддерева, вне зависимости обернут колбек в useCallback или нет. Справедливости ради, в твоем примере родитель не имеет своего локального состоятия или пропсов используемых только в родителе, поэтому у тебя все корректно. Но все же в общем случае, даталь описанную выше, нужно учитывать.
В большинстве случаев да, но есть и другие более редкие кейсы, когда тебе нужна одна и та же ссылка на функцию. Например если у тебя есть window.addEventListener и window.removeEventListener, в таком случае нужно так же передать одну и туже функцию, иначе ты не сможешь отписаться от события.
Видео отличное! У нас на проекте используют часто не по назначению. Подниму эту тему. Благодарю! Придерусь только к названиям обработчиков: 7:57, у них должен быть префикс `handle`. Ты и сам в видео говоришь, о том, что надо обработать (to handle) событие: handleClick, handleChange, handleSubmit, handleMyOwnClick, etc. Если это событие передаётся дальше как пропс, то префикс будет `on`: onClick, onChange, onSubmit, onMyOwnClick, etc. Ещё раз благодарю за видео! :)
Спасибо!) делать дальше это без проблем) а вот с чаще немного сложно. Сам контент, каждый выпуск это как статью на хабре написать (по некоторым выпускам мы и публикуем статьи), выматываем достаточно, а еще и видео ряд нужно придумать и смонтировать) Поэтому текущая наша скорость 1 видео раз в 2 недели
Внезапно правда хороший видос. Про этот "нюанс" знал, но уровень подачи материала на уровне. Разве что в какой-то момент объяснение кажется сверх-монотонным, а в какой-то слишком быстро проматывающим основные моменты. Например зачитывание на экране того, что я могу поставить на паузу и сам быстро прочитать. А потом скип, когда пишется функция useCallback.
@@it-sin9k когда показывалась реализация функции вместе с ее условиями, то например, мне хотелось самому же прочитать эти условия, так сказать зафиксировать их у себя в голове, а не просто пробежаться по ним. Как бы там не было ничего сложного, но хочется большой остановки на этом. Смотрю сейчас доклад, как же бодро ты рассказываешь, хочу с тобой работать)
Я просмотрел заново видос) понял о чем ты говоришь, я специально не останавливался особо на реализации useCallback, потому что через пару видео планирую эксперементальное видео, рассмотреть исходники реакта. Т.е. все смогут подробно увидеть, что примерно происходит под капотом. Конечно всю кодовую базу не получится раскрыть, но что-то получится
крутой контент, почему так мало подписчиков и просмотров. Не понимаю, почему только сейчас спустя можно сказать 2х лет ютьюб предложил ваши видео. Очень четкая и поставленная речь(только благодаря ей уже включаешься в осмысление темы) , продуманный текст, столько трудов.
@@user-bt9hx3ik6e что то подобное планируется, но будет думаю еще не скоро, платформу решили свою запилить для этого. Там много идей, что на ней можно запилить
Привет, тут небольшая ошибка 3:55. Eсли произойдет перерендер родительского компонента Test, тем самым Test сам начнет свой перерендер, даже если его пропсы не поменялись. В этом случае функция useCallback вернет закешированный callback, а в примере без useMemo произойдет пересоздание функции. И также в примере компонент Car нужно обернуть в memo, чтобы от мемоизированного коллбека была оптимизация
Не совсем понял мысль на 8:50 минуте - почему в этом случае нет смысла использования useCallback? Про оборачивание какой функции идет речь: onClick в или onCarClick в ?
Идея в том чтобы оборачивать в useCallback метод onCarClick, который находится в компоненте Cars. Это нужно для того чтобы компонент Car получал одну и туже ссылку на функцию, тогда компонент Car можно обернуть в memo и благодаря тому что ссылка на функцию будет одна и таже, компонент Car не будет заново рендериться, на каждый чих родителя. С другой стороны внутри компонента Car нет смысла оборачивать onClick. useCallback(() => onCarClick(car), [onCarClick, car]). Потому что нам нет нужды в одной и той же ссылке, пусть на каждый render функция новая передается в
@@it-sin9k > компонент Car не будет заново рендериться, на каждый чих родителя. На сколько я знаю компонент рендериться при новых пропсах или стейте и получается при новых пропсах ({cars}) компонент будет рендериться и за счет этого его потомки тоже Т е useCallback в тоже не имеет смысла?
Если компонент Car не обернут в memo, тогда Car будет рендериться абсолютно при любом рендере родителя. В данном примере я подразумевал, что компонент Car обернут в memo. Это значит, что компонент Car будет рендериться, только в случае, если хотя бы один из props изменится. Одним из таких props может быть функция onCarClick. Если мы не обернем ее в Cars в useCallback, тогда мы будет передавать новую ссылку на функцию, при каждом рендере Cars, а это значит что абсолютно все компоненты Car будут рендериться. Поэтому и оборачивается в useCallback, для того чтобы мемоизировать функцию, и каждый раз в props передавать одну и ту же ссылку на функцию onCarsClick
Привет видео класс. Хочу попросить вставлять в описание к видео ссылку на статью, твои же многие видео имеют статью на хабре. Полезно после просмотра еще и почитать то же самое, лучше закрепляется)
Тут 2 проблемки :) - Не хочу трафик с ютуба на хабр отправлять, идея была скорее наоборот) - ну и статьи давно перестал выпускать новые, что то комменты на хабре иногда меня очень расстраивали. Комменты на ютубе куда более приятно читать и отвечать людям Есть мысли сделать свой ресурс, куда расшифровки публиковать, тогда точно буду постить)
1. Немного не понял зачем нам создавать новую функцию из пропа в компоненте , почему мы не можем в return сам проп функции передать? 2. А если бы нам нужен был ивент, можем ли мы просто сделать onCarClick(car, event) }> ? 3. Видел что снизу в коментах про мемо речь ишла. Так нужно ещё и саму функцию в useMemo hook? Или компонент в memo HOC? Видосы топ! Качество огонь. Подача для джунов - на высоте! Побольше контента, спасибо! Будем лайкать и коментировать, а также ДОНАТИТЬ)))
1. Дело в том что компонент Car обернут в memo(). Соответственно чтобы избежать лишних рендеров, нужно передавать ссылку на одну и ту же функцию, а если создавать функцию снаружи, то вы каждый раз передаете новую ссылку на функцию. Да и саму функцию создаете, на каждый рендер листа, а если он в компоненте, то функция создавалась бы только при перерендоре 2. Так и сделано же 3. Для функции есть useCallback, а не useMemo. Да при работе с листами, чтобы передавать одну и ту же ссылку на функцию лучше обернуть ее в useCallback
@@it-sin9k, спасибо большое за ответ, но все же, либо я туплю, либо вы не совсем поняли вопрос 1. У меня ситуация идентичная как у вас в примере, за исключением того, что функция onCarClick принимает кроме car, ещё и event. Так вот. 1. В обернул объявление функции в useCallback, чтобы ссылка оставалась прежней. 2. Обернул компоненту в memo-HOC. 3. Но в я НЕ создаю по новой "const onClick = () => onCarClick(car, event)", по тому что, в return нужно ивент "поймать". Тоесть получается "return ( onCarClick(car, event)} />)" - каждый раз анонимная функция передается. Если бы я объявил ранее, то как бы переданая ссылка ивент поймала? Либо я просто не знаю как правильно сделать :( Как тогда оптимизировать?
@@_ivanoleksiukНе вижу в этом никакой сложности, вы вполне можете написать следующий код: const onClick = (event) => onCarClick(event, car) return click me
@@it-sin9k спасибо большое! Не знал что так работать будет. У меня два аргумента в функции, один из них ивент. Я думал будет работать если только два передавать. Думал всегда нужно анонимную с указанием двух. Не понимаю откуда берет второй (указываю "const onClick = (event) => onCarClick(event);" и работает). Но ничего - разберемся!
Суть useCallback в том, что someFunction будет мемоизирована И react не будет ререндерить атрибут onClick тега button, потому что someFunction мемоизирована (если конечно title не изменился) Поэтому данное видео для понимания useCallback под копотом хорошее, но неверное Поправьте если не прав
Похожая дискуссия происходила на хабре, если интересна выжимка (я придерживаюсь того же мнения), то склонялись к тому что onClick пере присвоить (addEventLister / removeEventListener) дешевле чем прогонять данные через useCallback. И читабельность ухудшается. Вот ссылка на тред, более подробно почитать можно мысли разных людей habr.com/en/post/529950/#comment_22379830
Я долго размышлял и понял, что в последнем примере ошибка, если я неправ, поправьте меня. Компонент Car все равно будет рендерится. То есть функция будет все равно отрабатывать, единственное, не будет removeEventListenet и addEventListenet . Чтобы действительно не было лишних срабатываний, нужно компонент car обвернуть в memo
Обработчики событий также будут обновляться при каждом рендере, так как при перерендере родителя перендеривается Car полностью, соответсвенно функция запускается полностью по новой
@@user-nd5zd5kc5k Да , все верно. Но только компонент в React.memo. Не совсем понял про removeEventListener и addEventListener. Почему они не будут срабатывать? Да и операция простейшая , имхо она легче чем useCallback
@@MrKu39 если добавить useCallback, но не добавлять React.memo, как в примере из видео, то оптимизация сведется к тому, что компонент (функция) все равно будет полностью срабатывать, будет видеть, что обработчик функции не изменился и не будет лишнего removeEventListenet и addEventListenet, которые были бы без useCallback
Хорошее видео В бета доке реакта указано, что useCallback можно представить в следующем виде: // Simplified implementation (inside React) function useCallback(fn, dependencies) { return useMemo(() => fn, dependencies); } В таком случае мы создаём целых две функции на каждый рендер вместо одной
топ спасибо за труды. Можно вопрос про часть (Таким образом все компоненты Car не будут рендериться лишний раз, т.к. ссылка на функцию останется прежней.) это утверждение верно если Car обернут в memo так? 8:35 минута.
Что если мы используем функцию внутри useEffect или useMemo и она передаётся в качестве зависимости в массив зависимостей, даст-ли нам пользу в производительности если мы эту функцию обернем в useCallback?
В конкретно этом видео, для наглядности. А в реальных проектах, мы обычно на 100% разделяем логику и отображение. Поэтому этот код у меня был бы в хуке кастомном, где я подготавливаю все данные для компонента
Спасибо! Очень круто и понятно! Есть только один вопрос: зачем в компоненте с кнопкой, при передаче props ссылки на функцию - создаётся новая функция, которая связывает эти функции?
То, что useCallback не кеширует функцию компонента между рендерами того же компонента (поскольку сам он обновляется полностью) - звучит очевидно да, но в таком контексте как озарение. Но вот почему при обычной передаче пропса нескольким дочерним компонентам передаются будто разные функции, хотя по логике ссылка должна быть даже, ведь сам родительский компонент за этот период пересоздаваться не должен, не понятно… Извините, пока сильно туплю в React.
Большое спасибо за труд, какой день изучаю этот useCallback =) немного не понял в конце 8:45 когда сам дочерний компонент обвернул в свою функцию. что изменилось что не нужно родителю использовать useCallback ? какие признаки должны быть когда точно нужно юзать useCallback?
@@it-sin9k А если заглянуть внутрь компонента Car. там мы создадим еще одну функцию, которая свяжет onCarClick и объект car. В этом случае нет никакой пользы оборачивать метод в useCallback, т.к. нам не важно, ссылка это на функцию с прошлого рендера или с текущего рендера... тут наверно про использование нового useCallback уже для Car? Наверно я не так понял, думал что продолжаете говорить про родительский useCallback, что в нем теперь нет необходимости. Спасибо!)
useCallback у родительского компонента нужен был, чтобы при рендере списка машин, все компоненты Car не обновлялись, чтобы все получали одну и ту же ссылку. А внутри Car там уже не важно, что мы передаем в onClick. На уровне DOM дерева можно и разную ссылку передавать, это дешевая операция
8:52 - не совсем понял, почему в данном случае неважно, почему не юзать useCallback на этом уровне - какой критерий, на каком уровне остановиться? Можете объяснить другими словами подробнее?
@@it-sin9k ход моих мыслей - полный хаос с этой меморизацией в голове, вроде много лет продакшн опыта, но никто в командах никогда не уделял этому такое внимание и писали почти везде useCallbak на каждый хендлер. Но тут возможно имеет место быть и атомарность данного компонента, так что тут useCallback бессмысленен, button не может обновиться без обновления внешнего Button по идее
@@awakeupcall5336 "тут useCallback бессмысленен, button не может обновиться без обновления внешнего Button по идее" (с) А даже если компонент обновится по другой причине и onClick создастся заново. Какой вред это причин по вашей версии?
Чем больше таких видео про "тонкости" работы хуков, тем больше понимания, какое же это говно. Ребята из команды реакта хотели упростить работу с компонентами и состоянием, но в итоге все эти правила и рекомендации работы с хуками вносят больше непонимания, вреда и сложности.
Есть вопрос. Я не понимаю, что значит не происходит повторных рендеров? Вот функция с компонентом ведь отработает в любом случае, если в родителе изменились state?
Если я правильно понимаю, то есть смысл использовать useCallback только в 2 ситуациях, если у нас мемоизирован компонент, либо если функция в зависимостях у useEffect или типа того
Спасибо за труды! Я так понял если не указывать deps, то useCallback будет рендериться каждый раз и толка от нее не будет, т.е. указывать deps обязательно, даже если это просто [] который будет создавать callback только в момент монтирования. Поправьте если я не прав
привет! хороший контент. как для вас удобнее отправлять чашку кофе, на патреоне или как спонсор в ютубе? Ваши видео стоят того. Возможно и я смогу вам чем-то помочь кроме спонсорства :)
Честно говоря мы еще сами не разобрались, что лучше подписка на патреон или спонсорство на youtube) поэтому где вам удобнее) А по поводу последнего предложения, мы рады любой помощи) Поэтому напишите на почту blue.sin9k@gmail.com, а там обсудим)
@@it-sin9k вместо юсКолбэк можно использовать функцию высшего порядка и в первом аргументе получаем результат функции вызванной в мапере на обработчик онКарКлик={функция(car)}. Не могу написать код, потому что ютюб его удаляет (((
@@sergiogusto Так функция высшего порядка вернет всегда новую ссылку в onCarClick. Что ломает memo. А useCallback занимается именно кешированием старой функции
Получается, если мы передаем функцию someFunc как пропс, а в дочернем компоненте создаем функцию Func, которая будет вызывать someFunc -> в этом случае в useCallback можно не оборачивать someFunc?
Привет! Немного не понял момент с собственным написанием useCallback. Вначале ставишь условие, что при отсутствии массива зависимостей (в prevState или переданный ) приравнять оба поля и вернуть коллбек, но точно такие же действия ставишь и в конце ф-ии, в чем заключается смысл, можно ведь просто убрать начальное условие и оставить условие с сверкой массива зависимостей?
Пришлось даже пересмотреть все видео, чтобы понять вопрос) На будущее бросайте тайм код, чтобы не искать)) А так ваши рассуждения абсолютно верные. По идее можно было бы просто сравнить на shallowEqual() и все тут. Почему же я поступил иначе. Я не выдумал этот код, я лишь упростил реальные исходники useCallback. Поэтому вышло немного не очевидно. Но как вы понимаете не в этом суть видео :)
Вы в корне не правы и вводите в заблуждение ! Без React.memo в дочернем компоненте не имеет смысла оборачивать функцию , переданную в пропсах ,в useCallback! Так как при перерендере родителя ВСЕГДА запускается перерендер дочерних компонентов. Хоть бы написали верно на Хабре или закрепили здесь под видео.
В данной реализации не очень эффективно выносить вверх. Так во всем компоненты мы передаем одну и ту же ссылку на функцию. И благодаря этому React.memo, помогает нам предотвращать рендеры. А если вынесем на уровень map создание функции, то всегда будет новая ссылка на функцию и тогда React.memo не будет никогда работать
Спасибо большое за крутой контент! Есть один вопрос по поводу ответа на 3:41: разве ф-я "someFunction" не будет создаваться реже в случае useCallback? К примеру если у нас компонент Test отрисовывается в родителе Parent и причиной отрисовки Parent является не смена "title", а что-то другое - то компонент Test все равно будет перерисовываться. А в случае useCallback ф-я "someFunction" будет создаваться только когда меняется "title". Это если бы у нас ф-я Test была обернута в React.memo - тогда да, отвел был бы "ни в каком". Но да, цена использования useCallback в этом случае намного дороже нежели цена создания ф-ии "someFunction". UPD: и также на 8:35 все компоненты Car будут перерисовываться если компонент Cars будет перерисовываться (потому что Car не обернут в React.memo), хоть и ф-я "onCarClick" обернута в useCallback.
нет, не будет. функция создается всегда. useCallback лишь может принимать решение. Вернуть вам функцию только что созданную или мемоизированную. А история про Test и useMemo это уже другая тема
@@it-sin9k Хм, я писал подробный комментарий к этому видео, но сейчас его нет. Хочешь сказать youtube удалил? Сохрани в массив все someFunction после объявления и сравни. В обычном случае они всегда разные. В случае использования useCallback только в первый будет отличаться. Видимо реакт создает какую-то заглушку функции.
все же как-то расплывчато когда использовать юзколлбэк, а когда нет. правильно ли я понял, что полезно только когда многократно используется то что мы в него завернем?
нет, useCallback нужен, только если вам важно, чтобы получать каждый рендер одну и ту же ссылку в памяти на функцию.А причины могут быть разные, зачем вам это нужно. Самая популярная, если вы передаете эту функцию в компонент обернутый в memo.
Хотел бы спросить: Правильно ли я понимаю - если есть дочерний компонент, ререндеры которого очень дорогостоящие, то, в таком случае, мы оборачиваем функцию, которую передаем в него, в useCallback. Вопрос вот в чем - допустим, в этот дочерний компонент мы передаем 5 функций. Если я не оберну хотя бы одну функцию в useCallback, то обернутые остальные 4 функции не имеют смысла(т к при ререндере родительского компонента, из которого мы эти функции передаем в дочерний, ререндерится эта одна единственная необернутая функция, что заставляет ререндерится дочерний компонент)? Заранее спасибо за ответ!
@@it-sin9k вы имеете ввиду, что во втором параметре мемо все обрабатывать как обычно, кроме конкретно этой, необернутой функции. Именно ее обработать таким образом, что если меняется ссылка на нее, то все равно не вызывать ререндер?
@@ivanMoldovanu есть такая возможность, если вам нужен рендер, только например когда 1 из 5 props иеняется, мы можем написать проверку в react.memo, чтобы только его сравнивать и в таком случае не важно, новая ссылка на функцию пришла или старая
Скиньте, пожалуйста, ссылку, где разработчики реакт так сказали: И конечно, доверяйте реакту, если они сказали лучше создавать функцию на каждый рендер, так и делайте, ведь они заинтересованы только в улучшении перформанса вашего проекта
Выбора у нас особо нет. Если используешь хуки, значит создаешь функцию на каждый рендер. Вопрос тогда сводится к следующему: классы или функциональные компоненты? Ответ здесь: ru.reactjs.org/docs/hooks-faq.html#are-hooks-slow-because-of-creating-functions-in-render
@@it-sin9k спасибо за оперативный ответ) Уточню, а то я немного запуталась. Под "лучше создавать фун-ию на каждый рендер" подразумевается использование хуков? Или речь о том, чтобы не используя хуки, позволить пересоздавать функцию (которую пытаешься передать в колбэк хука)?
Честно говорю я уже теряю суть вопроса)) В видео я пытался показать, не пишите классовые компоненты, а пишите функциональные компоненты. Но в функциональных компонентах может показаться, излишним создание функции например const onClick = {} на каждый рендер. Так вот это не проблема, просто смириться с этим надо))
А мне, кажется, вы не учли тот факт, что мемоизированную функцию нужно передавать именно в Оптимизированный дочерний компонент, и это значит, что в вашем случае компонент внутри должен быть обернут в React.memo, а иначе это не имеет слмысла
Да, все верно. Я в видео явно не показал, что оборачиваю компонент в React.memo. Но это имелось ввиду, я не помню уже честно говоря, проговаривал ли я словами это
@@it-sin9k передать в качестве аргументов в функцию, которая вернет уже функцию для он клика. Зачем каждый рендер пересоздавать одни и теже функции и окружения, если их можно создать один раз?
Какое-то странное объяснение работы useCallback. Понятно, что мемоизация не бесплатная, но при некотором большом числе зависимостей становится выгодно мемоизировать функцию. Об этом не было ни слова. Что опять может внести неправильное представление в головы разработчикам. Так сказать, другая крайность.
@@it-sin9k я про те зависимости, которые идут вторым аргументом (deps). И чем реже меняются эти зависимости, тем больше попаданий в кэш. Соответственно выгодней использовать useCallback.