Функция loadBooks вообще может быть вынесена из компонента. Она может принимать categoryId и возвращать response.books. А в useEffect ее вызываем (await loadBooks) и просто делаем setState() для результата. Тогда сама функция будет создана 1 раз.
Как я в начале видео и говорил, способов написать один компонент очень много. Поэтому основная идея была, покрыть 1 рабочий кейс. Чтобы показать что можно делать и так тоже. Судя по комментариям, некоторым это пригодилось. Да я и сам писал сразу неправильно)
Чтобы вызвать функции с помощью await, придется пометить функцию эффект как асинхронную, что автоматически приведет к возвращению промиса из нее, однако же реакт ожидает, что функция эффект будет возвращать другую (clean-up) функцию. Как следствие - ошибка
Хорошая работа! Но есть пару заметок ( Вижу, что видео старое, может мои заметки показаны в след. видео) 1. Почему бы нам не вынести функцию за пределы компонента? Зачастую методы для работы с АПИ продакшене выносятся в отдельные файлы. 2. Лучше всего деструктуризацию проводить в теле функции. Понимаю, что в наглядном примере это смотреться адекватно и экономит нам строку. Но новичкам такой подход нравится и начинаю деструкторизировать по 10-15 свойств ( в шапке функции), этим самым усложняя читабельность кода :) const loadBooks = (categoryId) => { return api.getBooks({categoryId}); } const Books = props => { const {categoryId} = props; const [books, setBooks] = useState([]); useEffect(()=> { loadBooks(categoryId).then(response => { setBooks(response.books); }) }, [categoryId]); return ... }
@@it-sin9k да вроде стараемся, в дискорд rolling scopes вас кидал, вообщем думаю будет геометрическая прогрессия. Только не бросайте канал, если надо донаты, буду донатить, очень верю в вас
Спасибо за поддержку!) Думаю в ближайшее время появится кнопка спонсировать канал) Бросать не планируем) обдумываем только варианты монетизации, думаю из пары экспериментов, что-нибудь получится)
Топ🔥🔥 Получается, что callback из return эффекта срабатывает, если какая то из зависимостей меняется, либо происходит размонтирование компонента? И насчёт последнего примера. В классическом приложение есть состояния загрузки и пользователь все равно не увидит результат, но пример очень интересный
А какой в принципе смысл добавлять loadBooks в зависимости useEffect в первом кейсе ? Если допустим у нас будет просто [ ] , то что-то изменится ? Loadbooks ведь может измениться ровно из-за изменения 1 зависимости ( сategoryId) , которая в свою очередь является props`ом , а изменение props`а влечёт за собой полный ререндер компонента . Это имело бы смысл , если бы мы как-то меняли этот id уже в самом компоненте , что конечно просто нонсенс. Я что-то упустил ?
Насколько я понял, фишка в том что useEffect срабатывает тогда когда компонент отрендерился, значит мы безопасно можем посылать асинхронные запросы на сервер, иначе react не гарантирует правильность своей работы. Могу быть не прав, но скорее всего это из-за этого
Спасибо, полезный материал! Первый варинт вполне удобен, если что то тоже пользуется этой же async функцией в рамкам компонента (или его дети). И второй удобен. Все как всегда зависит от задачи)
Может рассмотрим подробнее темы, связанные с уменьшением дублирующего кода, создание абстракций для работы с сущностями в проекта, какой-то слой сервисов для преобразования данных для отрисовки, чтобы не прям в верстке логика была)?
Чтобы перейти к обсуждению более архитектурных вещей, хотелось бы сразу пройтись по базе, условно понимать хорошо как работает key или какой то хук. Имея такие видео, я могу на них ссылаться в будущих видео. Это как программа в школе, сначала надо научиться складывать и умножать прежде чем считать площадь квадрата. Но вообще я сейчас создал голосовалку, на то, что вы хотите увидеть после темы хуков - twitter.com/it_sin9k
Еще как альтернатива переменной и более нативный метод для отмены запросов существует встроенный класс, который возвращает инстанс контроллера со свойством signal
вооо, вот это я понимаю - действительно полезный видос для меня, респект. Как раз таки сегодня хотел гуглить о том зачем ставят флаг в useEffect, и тут сразу ответ нашел) Недавно как раз писал dashboard и была проблема подобная и не знал как решить, ну теперь явно закреплю практикой всё это дело.
Спасибо, я как то даже не задумывался об отмене запроса, если её не сделать то может последний ответ придти раньше, тогда старая категория перезапишет нужную пользователю
Очень крутые ролики спасибо за контент !❤ Микро вопрос зачем создавать булавы переменные и затем инвертировать их If(! isIgnoreResponse) … Почему бы сразу не объявить переменную с отрицанием например shouldProcessResponse вместо isIgnoreResponse Или возможно есть какая то конвенция или бест практис Заранее благодарю 🙏🏽 7:56
@@someChicoRy Например можно создать переменную hasPermissions, а тебе нужно написать if где, если у человека нет пермишеннов, то сделать что то. В таком случае теоретически можно создать переменную hasNoPermission. И вот такие переменные я стараюсь не создавать. В таком случае либо подумать как вообще переименовать ее без No чтобы была, либо восклицательный знак использовать
1) Не повредит, просто читать непривычно 2) да, конечно, единственное, а что если запросов несколько или у тебя еще вычисления после запроса. И именно в этот момент анмаунтится страница, все равно есть гэп
@@it-sin9k 2) С его вы взяли, что сразу будет получен респонс 2, а не 3? Задержки сети, разная сложность запросов. На простом примере конечно оно всё красиво выглядит
Здравствуйте. Отличное видио, спасибо большое. Можете пожалуйста сделать видео от том как вообще проектировать и разрабатывать компоненты в React вместе с Redux, так чтобы избегать пробросов пропрос в глубину через дочерние компоненты(и обходится без React Context) и делать компоненты более независимы и более переиспользуемыми? Стоит ли использовать хуки useSelector и useDispatch или использовать по старинке connect для Redux?
Спасибо, да вполне могу такое видео сделать. Но тем очень много и все хотят разные темы услышать. Поэтому я организовал голосовалку и предложил разные темы, чтобы понять, что люди хотели бы услышать в первую очередь. И тема редакса там тоже есть. Здесь вы можете найти голосовалку - twitter.com/it_sin9k
к сожалению на такие вещи книги тяжело написать, т.к. все приемы могут стать очень быстро не актуальными. Есть шанс, что когда книгу будешь дописывать, она уже станет не актуальной и выбросишь все труды. В моем случае единственным вечно актуальным источником является реакт документация. Поэтому я и решил завести этот канал, в котором я смогу поделиться многими мыслями, как я пишу проекты свои. Но каждый выпуск это много времени и сил 2-ух человек, которые после работы все это делают. В итоге наш предел 1 выпуск в 2 недели
А как лучше поступать, если функция loadBooks так же будет нужна внутри jsx. Например у нас есть кнопка refetch. Тогда использование use callback будет правильным решением или есть другой способ?
Мы очень рады быть полезными) у нас еще много разных тем, которые мы хотим вам рассказать) Поэтому подписывайтесь и нажимайте колокольчик, ведь у нас нет спама)
Такой код немного опасен, для вашего приложения. Первая проблема, это вызов обновления стейта (setCategory) до, того как рендер закончится. Как реакт должен себя правильно вести себя, когда построение текущего виртуального дома не закончилось, а вы уже призываете к следуюзему рендеру? А вторая проблема, это вызов запросов во время рендера. Основная идея, в том, что у реакта есть свой жизненный цикл, когда стоит начать отправлять запросы (в useEffect). И если вызывать прямо в рендере, то реакт в некоторых ситуациях, не сможет гарантировать правильную работу приложения. Это будет на вашей совести, потому что пользуете фреймворком, не так как предпологают реакт разработчики
Знаю, что такую проблему, что указана в бонусе, можно решить rxjs и оператором switchMap, оператор просто оменяет предыдущий запрос, когда тригерится новый. Я хочу уточнить, насколько корректно использовать rxjs в мире реакта?
Мы использовали, я притащил на проект и это было очень круто. У нас даже не возникло многих проблем, которые без него люди героически решают. Включая проблему из видео, нам не нужно создавать функцию, мы просто подписались бы на событие и поставили бы значение, которое получили. Вся проблема в том, что нужно вызвать асинхронным функцию.
Мне кажется (уверен процентов на 90), что раньше на сайте Redux в разделе FAQ был вопрос про RxJS и был ответ, что если вы используете RxJS, то вам нафиг не нужен Redux.
я понял о чем речь. В примерах в React документации, часто используют function вариант для методов. Даже при создании компонентов, они часто там пишут function Example() { return test } Но я думаю они это делают, для упрощения понимания примеров. Т.к. в create-react-app уже генерится компонент в виде стрелочной функции. Влияет ли это как на перфоманс, я думаю вряд ли. Это очередной подсчет спичек. Возможно стрелочные функции чуточку быстрее из-за того что не имеют имени и можно сразу в onClick передать и контекст работает иначе у стрелочной функции callSomeMethod(data)}>test Поэтому выберите просто более удобный синтаксис и не парьтесь)
Я не писал еще на recoil, даже на тестовых проектах, только читал доку. По первому впечатлению это redux нового поколения. Мы текущий проект на MobX пишем в крайне похожем стиле. Поэтому может организуем на работе прототип, чтобы оценить, возможно он нам больше подойдет
нет) но выглядит как будто они увлеклись набором абстракций) нужно стараться делать все проще и хотелось бы меньше черных ящиков, а больше чистого js. По крайней мере на больших проектах :)
Может и попробую. Настораживает, только то что у них 21 релиз, а на слуху так и не появился. Обычно хорошие либы быстро всплывают в разных статьях / видео / конфах.
Я даже не припомню кейса , где бы нужно было в зависимость функцию передавать , Я обычно создаю функцию вне эффекта , а в эффекте вызываю ее передав в нее параметр categoryID например
Это значит, что ваш стек или ваши подходы к организации кода, полностью искореняют возможность такого кода. Например, мы сейчас пишем приложение используя mobX и там действительно нет никакой нужды делать такого рода конструкции, но в более простых pet проектах, я сталкивался с такой проблемой :)
@@it-sin9k Ну на сколько я понял, задача стоит в том , что при новом categoryId мы вызываем функцию , getBooks , но в этой функции мы используем пропс переданный в компонент , то есть , при входе на страницу , мы вызовем при монтировани страницы useEffect вызовет функцию и мы получим книги , указав зависимость categoryId мы получаем тот же результат , и при создании функции внутри хука при монтировании и при зависимости от категории , тот же результат
Да, абсолютно верно размышляете. Один лишь момент, который я уточнял, это то что многие могут использовать eslint плагин на проверку зависимостей. Поэтому я решил исходить из того, что вы используете eslint-plugin и он вас заставил бы добавить функцию как зависимость. Но функцию добавлять не хочется, так как выглядит слишком сложно тогда конструкция. И данное видео как раз является примером решения такой проблемы
5:28 а какой смысл выделять пямять чтобы дать функции название, если она сразу же вызывается? Можно просто создать самовызывающуюся анонимную стрелочную асинхронную функцию: (async () => { await ... })()
Да можно и так сделать :) Я использую чаще всего функцию с именем, потому что самовызывающиеся функции в коде почти никогда не встречаю в коде. Соответственно людям сложнее читать код.
я расскажу свое видение из кода, который я прочел и обрывков фраз, которые я слушал на выступлениях на конференциях официальных от React Core team. "Hook" в переводе с английского языка звучит как "Крючок". Допустим у нас есть компонент у которого есть useState(6). И как вы знаете эта цифра 6 будем доступна при первом рендере, втором или любом другом рендере, пока вы на одном из рендеров ее не перезапишите. Как перезапишите будет другое значение хранится в state. Хотя ваш компонент это всего лишь функция, а у функции как вы знаете не существует this. Где тогда хранится эта цифра 6? Ответ прост, они сохраняют цепочку вызванных хуков условно в "глобальной переменной" и при новом рендере они крючком цепляются за туже "глобальную переменную". Т.е. хук это не что иное как просто придуманная абстракция с именем, которое React разработчики посчитали наиболее успешным. Таким же образом они могли назвать хуки - например Packages / BusinessLogic/ КотВМешке / КонопляНаБатуте
@@it-sin9k я думал, что хуки подвязаны для каждого фибера, если они глобальным обьектом, как тогда реакт понимает, что у конкретной ноды - конкретные хуки?
Они хранятся у конкретной ноды, я поэтому и написал "условно")) Я вот прямо сейчас расписываю новый выпуск и там как раз немного углубляюсь, про то как работают хуки) а пока рекомендую посмотреть это видео про исходники хуков - ua-cam.com/video/kcHEWut-DUA/v-deo.html
по факту вот в переменную currentlyRenderingFiber присваивается текущая fiberNode. И внутрь него в виде linkedList складываются все хуки github.com/facebook/react/blob/v17.0.1/packages/react-reconciler/src/ReactFiberHooks.new.js#L557 А при повторном рендере из currentlyRenderingFiber.alternate достается linked list из прошлого рендера github.com/facebook/react/blob/v17.0.1/packages/react-reconciler/src/ReactFiberHooks.new.js#L573 И начинается создание нового linked list. И в этой строке они берут данные из прошлого хука и сохраняют его в текущий хук github.com/facebook/react/blob/v17.0.1/packages/react-reconciler/src/ReactFiberHooks.new.js#L606
а какой смысл нам ждать конца выполнения этой функции? Более того наоборот, нужно скорее вернуть в return функцию, недожидаясь ответа от сервера, чтобы если deps изменяться, было что вызвать :)
@@it-sin9k ну чтобы у нас true не проставился в игнор еще до того как с сервера пришли данные. ощущение что данный код никогда не добавит книгу хуки блочат рендер пока не будут завершены? await на сетевой запрос это уже браузер API, поэтому браузер может не блокировать основной поток нашим ожиданием промиса
Я думаю вы упускаете несколько важный моментов: - в return мы возвращаем функция, вызов которого откладывается до изменения dependencies, т.е. isIgnoreResponse не изменяется до того как зависимости не изменятся - абсолютно для каждого вызова функции переданной в useEffect создается своя переменная isIgnoreResponse. Я вас точно уверяю, что код рабочий, вам стоит попробовать написать и поиграться с ним, чтобы вникнуть :)
несмотря на то что автор не ответил на предыдущий мой комментарий все же добавлю. если функция которая загружает не из пары строк состоит и она используется так же и в другом месте, то пихать ее в эффект совсем нехорошо, поскольку придется ее и в другом месте дублирлвать. получается дублирование кода и загромождение эффекта. не все так однозначно.
сорри, что пропустил другой ваш вопрос. В данном вопросе вроде как размер функции не имеет значения. Вместо api.getBooks() будет какая то кастомная функция, но суть вроде как не меняется const books = getBooks(...) // some custom function setBooks(books)
А если не указывать loadBooks как зависимость и не идти на поводу у eslint? Тогда никакого лишнего кода, читаемость лучше чем с калбеками, а то что loadBooks каждый рендер создается пофиг, это вряд ли станет узким местом в программе
Это будет вполне себе работать. И читабельность будет терпимой. Только придется смириться с несколькими вещами: 1) отказаться от eslint правила следящего за зависимостями 2) смириться с тем что вы создаете функцию до того как контент отрисовывается в браузере, а не прямо перед ее использованием (офк это экономия на спичках, не сильно тянет как весомый аргумент) А так да вполне рабочий вариант, я бы даже сказал, лучше чем с useCallback
@@it-sin9k можно даже отмену запроса в эффекте реализовать, создать объект с полем отмены присваивания и просто передавать в функцию loadData, а в функции сброса менять это поле, useRef на коленках :)
7:10 пам пам, и 3 пришел раньше чем 2, ибо асинхронное общение с сервером, и первый запрос не гарантирует первый ответ, а ты потом радуйся жизни, ловя плавающий баг
Дока не пропагандирует подход, а предоставляет максимально простой и понятный код, для более быстрого и легкого понимания механизма и принципа работы. Самое рациональное решение - вызывать запрос в санке или саге. В хуке useEffect будет максимально понятное - вызов экшена и передача id в него и они же в зависимостях. Ты пропагандируешь лишнюю связанность кода. Компонент не должен знать о запросе.
Так код, который я предоставил, это пример из реакт документации) тогда получается из этих слова "Ты пропагандируешь лишнюю связанность кода", не я пропогандирую, а документация все таки)) Ну а если серьезно, то не одним редаксом едины. Сейчас уже не первый проект вижу тенденцию, что люди отказываются от того, чтобы всю асинхронщину совать в thunk / saga. Их мотивация заключается в том, что если ты используешь thunk, тогда тебе надо хранить информацию в redux. Если хранишь информацию в redux, а ты ее не планируешь глобально использовать, по разным причинам, например быстрой потери актуальности информации. Тогда тебе приходится еще чистить redux store, после анмаунта компонента. И люди решили, а зачем было вмешивать редакс в этот флоу? нельзя было просто в хуке сделать запрос показать лодинг и стейт сам очиститься после анмаунта? Особенно это актуально в RN проектах. Где тьма экранов, с мелкими запросами, и надо все равно приходится каждый раз перезапрашивать актуальные данные. В итоге, я все чаще вижу проекты, где люди прогоняют через redux, только те запросы и данные, которые действительно нужно хранить глобально. А если тебе не нужно хранить глобально, тогда вот такое написание кастомного хука часто можно встретить в проекте. paste.ubuntu.com/p/83zssmRhPR/ Более того, если писать сейчас на mobX проект. Скорей всего будете использовать mobx-react-lite, у которого весь код будет в кастомных хуках обернутых внутри в useLocalObservable) Поэтому если, вы решили использовать redux по максимуму в своем проекте, а реакт только для отрисовки, это не значит, что ваш подход лучший и все должны его использовать. Это лишь один из возможных вариантов написания сайта. Более того, я писал раньше код, так как вы предлагаете и продвигал в массы, что при таком подходе все однообразно просто и понятно. Но на дистанции. Сначала я отказался от Саги, т.к. она начала давать больше сложностей, чем пользы. Потом от redux-form, т.к. сам создатель либы от нее отказался, все по этим же причинам, чтобы не сотрясать лишний раз редакс. И в итоге отказался от хранения всех данных в redux) Просто делюсь своим опытом)
А глобальное хранилище не должно знать о данных, которые нужны только в рамках компонента. Компонент должен звать какой-то слой отвечающий за запрос данных, а лучше ещё промежуточный слой, который отвечает за логику выполняя роль application из DDD. Но все равно, он будет асинхронным, поэтому нету смысла усложнять пример... как и использовать Redux для запросов.
Как раз Redux для запросов и даёт лишнюю связанность кода, а если писать на чемоданчиком э человеческом TS (в крайнем случае JS), то потом код можно реально переиспользовать.
хотя как и под любым из найденных мною видео куча восторженных комментариев, особой сути рассказанного не много. зачем все лепить в эффект? если на конкретном примете где пара строк кода, то да. но глядя на это народ станет же все так лепить по десятку выполняемых задач в одном эффекте, когда гораздо лучше вызвать в нем отдельные функции каждая из которых занимается своим делом. в итоге в попытке оптимизировать, получается просто укрупнение. да и что сэкономлено непонятно. ни скорость выполнения не сравнили ни расход памяти. очень дорогих буков меньше? так можно было и еще сократить. функции короче называть можно, как вебпак сразу по одной букве. если и показываете что это хорошо, то уж сравнительные данные не помешают, а иначе весь этот подход к хорошему не доведет. я не сомневаюсь что Вы понимаете что делаете, а вот поймет ли смысл посмотревший это новичок, коих тут полно и которые как на второе пришествие на автора смотрят. а при любом применении любой оптимизации в первую очередь надо понимать для чего и стоит ли оно того. а так же последствия.
Я сходу не понял, нафига создавать функцию вместе того, чтобы потом ее отдельно вызывать. А потом понял, на какие костыли не приходится идти, если не используешь RxJS 🤣
Я создаю внутри useEffect самовызывающуюся функцию (async () => {...})(). В этом случае мне не приходится как то её называть и вызывать после создания. Нам ведь функция нужна для того , что бы сделать её асинхронной. Не знаю правда на сколько читабильно
мало мало очень мало такого хорошего контента ))) хочу больше React и с самого начала )))
мы работаем над этим) как раз монтаж следующего выпуска активно идет)
Мужииик, я просто обалдел, как ты крут и как полезен твой контент. Спасибо! Моя просьба продолжать бомбить про реакт и околореакт.
Ничего себе какие ярки эмоции вызывают мои ролики)) нам очень приятно)
будем стараться продолжать в том же духе)
Функция loadBooks вообще может быть вынесена из компонента. Она может принимать categoryId и возвращать response.books. А в useEffect ее вызываем (await loadBooks) и просто делаем setState() для результата. Тогда сама функция будет создана 1 раз.
Как я в начале видео и говорил, способов написать один компонент очень много. Поэтому основная идея была, покрыть 1 рабочий кейс. Чтобы показать что можно делать и так тоже. Судя по комментариям, некоторым это пригодилось. Да я и сам писал сразу неправильно)
Чтобы вызвать функции с помощью await, придется пометить функцию эффект как асинхронную, что автоматически приведет к возвращению промиса из нее, однако же реакт ожидает, что функция эффект будет возвращать другую (clean-up) функцию. Как следствие - ошибка
действительно, хорошее примечание!
Хорошая работа! Но есть пару заметок ( Вижу, что видео старое, может мои заметки показаны в след. видео)
1. Почему бы нам не вынести функцию за пределы компонента? Зачастую методы для работы с АПИ продакшене выносятся в отдельные файлы.
2. Лучше всего деструктуризацию проводить в теле функции. Понимаю, что в наглядном примере это смотреться адекватно и экономит нам строку. Но новичкам такой подход нравится и начинаю деструкторизировать по 10-15 свойств ( в шапке функции), этим самым усложняя читабельность кода :)
const loadBooks = (categoryId) => {
return api.getBooks({categoryId});
}
const Books = props => {
const {categoryId} = props;
const [books, setBooks] = useState([]);
useEffect(()=> {
loadBooks(categoryId).then(response => {
setBooks(response.books);
})
}, [categoryId]);
return ...
}
Супер контент, продолжайте пожалуйста
Спасибо! скоро выйдет новый ролик) по секрету тема будет React Server Actions)
лайк и комент для алгоритма
Спасибо!) Алгоритм работай!
Супер, спасибо за видео. Интересно наблюдать как можно по разному ипользовать каждодневные хуки.
Рады быт полезными :)
Редко такое бывает, но на этом канале хочется ставить лайк каждому видео)
Мы рады всем лайкам)
Спасибо большое за контент, давайте больше бест практисов, реально очень полезно знать)
Спасибо за труды, жаль мало подписчиков в отличие от всякого шлака. Подача и темы топовые!
Это еще мы знатно выросли)
первые 500 подписчиков вообще тяжело шли))
Поэтому нам будет очень приятно, если вы расскажете о нас своим коллегам!
@@it-sin9k да вроде стараемся, в дискорд rolling scopes вас кидал, вообщем думаю будет геометрическая прогрессия. Только не бросайте канал, если надо донаты, буду донатить, очень верю в вас
Спасибо за поддержку!)
Думаю в ближайшее время появится кнопка спонсировать канал)
Бросать не планируем) обдумываем только варианты монетизации, думаю из пары экспериментов, что-нибудь получится)
Топ🔥🔥
Получается, что callback из return эффекта срабатывает, если какая то из зависимостей меняется, либо происходит размонтирование компонента?
И насчёт последнего примера. В классическом приложение есть состояния загрузки и пользователь все равно не увидит результат, но пример очень интересный
А какой в принципе смысл добавлять loadBooks в зависимости useEffect в первом кейсе ? Если допустим у нас будет просто [ ] , то что-то изменится ? Loadbooks ведь может измениться ровно из-за изменения 1 зависимости ( сategoryId) , которая в свою очередь является props`ом , а изменение props`а влечёт за собой полный ререндер компонента . Это имело бы смысл , если бы мы как-то меняли этот id уже в самом компоненте , что конечно просто нонсенс. Я что-то упустил ?
Насколько я понял, фишка в том что useEffect срабатывает тогда когда компонент отрендерился, значит мы безопасно можем посылать асинхронные запросы на сервер, иначе react не гарантирует правильность своей работы. Могу быть не прав, но скорее всего это из-за этого
Божественно, спасибо!) несправедливое количество просмотров и лайков, алгоритмы давайте шевелитесь
Очень познавательно,спасибо ! useEffect by React Documentation
Спасибо, как всегда отличный материал и подача)
Спасибо :)
Спасибо, полезный материал!
Первый варинт вполне удобен, если что то тоже пользуется этой же async функцией в рамкам компонента (или его дети).
И второй удобен. Все как всегда зависит от задачи)
Все верно :)
главное оценить по 2-ум критериям, как выгоднее
Может рассмотрим подробнее темы, связанные с уменьшением дублирующего кода, создание абстракций для работы с сущностями в проекта, какой-то слой сервисов для преобразования данных для отрисовки, чтобы не прям в верстке логика была)?
Чтобы перейти к обсуждению более архитектурных вещей, хотелось бы сразу пройтись по базе, условно понимать хорошо как работает key или какой то хук. Имея такие видео, я могу на них ссылаться в будущих видео. Это как программа в школе, сначала надо научиться складывать и умножать прежде чем считать площадь квадрата. Но вообще я сейчас создал голосовалку, на то, что вы хотите увидеть после темы хуков - twitter.com/it_sin9k
офигеть какой контент! такого еще не видела
++ за пояснения с графом
Еще как альтернатива переменной и более нативный метод для отмены запросов существует встроенный класс, который возвращает инстанс контроллера со свойством signal
Спасибо! Очень крутой контент!
Можно еще сигнал (new AbortController) в api прокинуть и остановить запрос при unmount =)
Спасибо за видео.
Как всегда познавательно.
вооо, вот это я понимаю - действительно полезный видос для меня, респект. Как раз таки сегодня хотел гуглить о том зачем ставят флаг в useEffect, и тут сразу ответ нашел)
Недавно как раз писал dashboard и была проблема подобная и не знал как решить, ну теперь явно закреплю практикой всё это дело.
Круто! Думаю на канале еще много полезных видео!)
Нормально я зашел! По совету коллег
Добро пожаловать!)
Спасибо, я как то даже не задумывался об отмене запроса, если её не сделать то может последний ответ придти раньше, тогда старая категория перезапишет нужную пользователю
Все верно, это называется race condition ;)
Очень крутые ролики спасибо за контент !❤
Микро вопрос зачем создавать булавы переменные и затем инвертировать их
If(! isIgnoreResponse) …
Почему бы сразу не объявить переменную с отрицанием например
shouldProcessResponse вместо isIgnoreResponse
Или возможно есть какая то конвенция или бест практис
Заранее благодарю 🙏🏽
7:56
нет особой причины) видимо в тот момент мне показалось это более читабельным)
Слушай, а можешь объяснить, что ты имел ввиду? Если не булевые переменные, то что еще можно использовать?
Имею ввиду, что такое переменная отрицания?
@@someChicoRy Например можно создать переменную hasPermissions, а тебе нужно написать if где, если у человека нет пермишеннов, то сделать что то. В таком случае теоретически можно создать переменную hasNoPermission. И вот такие переменные я стараюсь не создавать. В таком случае либо подумать как вообще переименовать ее без No чтобы была, либо восклицательный знак использовать
спасибо. Плюс минус понял) @@it-sin9k
5:24 использование самовызывающейся асинхронной функции ничем не повредит, верно?
7:32 или можно использовать AbortController
1) Не повредит, просто читать непривычно
2) да, конечно, единственное, а что если запросов несколько или у тебя еще вычисления после запроса. И именно в этот момент анмаунтится страница, все равно есть гэп
@@it-sin9k 2) С его вы взяли, что сразу будет получен респонс 2, а не 3? Задержки сети, разная сложность запросов. На простом примере конечно оно всё красиво выглядит
@@yauhen9607 ну пусть придет 3-ий респонс раньше чем 2-ой. Какая разница? 2-ой респонз все равно проигнорируется, а 3-ий дождется и засетится
Здравствуйте. Отличное видио, спасибо большое. Можете пожалуйста сделать видео от том как вообще проектировать и разрабатывать компоненты в React вместе с Redux, так чтобы избегать пробросов пропрос в глубину через дочерние компоненты(и обходится без React Context) и делать компоненты более независимы и более переиспользуемыми? Стоит ли использовать хуки useSelector и useDispatch или использовать по старинке connect для Redux?
Спасибо, да вполне могу такое видео сделать. Но тем очень много и все хотят разные темы услышать. Поэтому я организовал голосовалку и предложил разные темы, чтобы понять, что люди хотели бы услышать в первую очередь. И тема редакса там тоже есть. Здесь вы можете найти голосовалку - twitter.com/it_sin9k
@@it-sin9k А книги какие можете посоветовать по React? Все что я находил 2016-18 годов.
к сожалению на такие вещи книги тяжело написать, т.к. все приемы могут стать очень быстро не актуальными. Есть шанс, что когда книгу будешь дописывать, она уже станет не актуальной и выбросишь все труды. В моем случае единственным вечно актуальным источником является реакт документация. Поэтому я и решил завести этот канал, в котором я смогу поделиться многими мыслями, как я пишу проекты свои. Но каждый выпуск это много времени и сил 2-ух человек, которые после работы все это делают. В итоге наш предел 1 выпуск в 2 недели
@@it-sin9k у вас отлично получается продолжайте в том же духе.
Круто, долго искал инфу, которую ты дал в качестве бонуса) спасибо за твой труд
лучший канал по react!
А как лучше поступать, если функция loadBooks так же будет нужна внутри jsx. Например у нас есть кнопка refetch. Тогда использование use callback будет правильным решением или есть другой способ?
Да, тогда нужно использовать useCallback
Спасибо большое за такой качественны и главное полезный контент!)
Мы очень рады быть полезными) у нас еще много разных тем, которые мы хотим вам рассказать)
Поэтому подписывайтесь и нажимайте колокольчик, ведь у нас нет спама)
классное видео, спасибо большое!!!
По поводу игнорирования ответа от сервера, рациональнее намного прерывать первый запрос и отправлять второй запрос
да, отменять запрос дело хорошее :)
очень полезный ролик, сразу подписался, спасибо за контент
Можете заодно стать нашим спонсором)
Хорошое объяснение, лайк )
Просто топ, почему так мало подписчиков ????
Самое интересное, что я видел похожий комментарий, когда у нас было всего 60 подписчиков, и когда стало 9000)) Вероятно мы еще далеки от предела)
@it-sin9k в чем плюсы/минусы вообще не использовать useEffect в данном случае
const Books = ({ categoryId }) => {
const [category, setCategory] = useState(null);
const [books, setBooks] = useState([]);
const loadBooks = async (id) => {
const response = await api.getBooks({ categoryId: id });
setBooks(response.books);
};
if (categoryId !== category) {
setCategory(categoryId);
loadBooks();
}
return ( ... )
}
Такой код немного опасен, для вашего приложения. Первая проблема, это вызов обновления стейта (setCategory) до, того как рендер закончится. Как реакт должен себя правильно вести себя, когда построение текущего виртуального дома не закончилось, а вы уже призываете к следуюзему рендеру?
А вторая проблема, это вызов запросов во время рендера. Основная идея, в том, что у реакта есть свой жизненный цикл, когда стоит начать отправлять запросы (в useEffect). И если вызывать прямо в рендере, то реакт в некоторых ситуациях, не сможет гарантировать правильную работу приложения. Это будет на вашей совести, потому что пользуете фреймворком, не так как предпологают реакт разработчики
Знаю, что такую проблему, что указана в бонусе, можно решить rxjs и оператором switchMap, оператор просто оменяет предыдущий запрос, когда тригерится новый.
Я хочу уточнить, насколько корректно использовать rxjs в мире реакта?
я периодически слышу, что где-то, кто-то использует rxjs, но никогда не видел своими глазами)
Мы использовали, я притащил на проект и это было очень круто.
У нас даже не возникло многих проблем, которые без него люди героически решают.
Включая проблему из видео, нам не нужно создавать функцию, мы просто подписались бы на событие и поставили бы значение, которое получили.
Вся проблема в том, что нужно вызвать асинхронным функцию.
Мне кажется (уверен процентов на 90), что раньше на сайте Redux в разделе FAQ был вопрос про RxJS и был ответ, что если вы используете RxJS, то вам нафиг не нужен Redux.
Контент кайф, продолжайте в том же духе
спасибо!)
Очень годно!!!
Спасибо огромное)
хорошо
Круто спасибо! По идее на стадии очистки эффекта можно ещё дополнительно абортировать запрос
Спасибо, оч крутые видео! *_*
Спасибо!) Лучшей благодарностью будет поделиться видео с коллегами)
useEffect by React Documentation
недавно только гадал, как правильнее) спасибо ответ
Thanks for your lessons!!!!!!!!
а если объявлять функцию как функциональное выражение это поможет оптимизации?
а что такое функциональное выражение? (лучше пример с кодом)
@@it-sin9k
const Example = () => {
*const exampleClick = () => {}*
return Example
}
const Example = () => {
*function exampleClick() {}*
return Example
}
разное объявление функций влияет как-то на оптимизацию?)
я понял о чем речь. В примерах в React документации, часто используют function вариант для методов. Даже при создании компонентов, они часто там пишут
function Example() { return test }
Но я думаю они это делают, для упрощения понимания примеров. Т.к. в create-react-app уже генерится компонент в виде стрелочной функции.
Влияет ли это как на перфоманс, я думаю вряд ли. Это очередной подсчет спичек. Возможно стрелочные функции чуточку быстрее из-за того что не имеют имени и можно сразу в onClick передать и контекст работает иначе у стрелочной функции
callSomeMethod(data)}>test
Поэтому выберите просто более удобный синтаксис и не парьтесь)
@@it-sin9k спасибо за ответ! :)
Спасибо.
Что думаете по поводу recoil от FB?
Я не писал еще на recoil, даже на тестовых проектах, только читал доку.
По первому впечатлению это redux нового поколения. Мы текущий проект на MobX пишем в крайне похожем стиле. Поэтому может организуем на работе прототип, чтобы оценить, возможно он нам больше подойдет
@@it-sin9k а про effector что-нибудь слышали?)
нет) но выглядит как будто они увлеклись набором абстракций)
нужно стараться делать все проще и хотелось бы меньше черных ящиков, а больше чистого js. По крайней мере на больших проектах :)
@@it-sin9k у меня было пару проектов с ним. Переписывали с редакса на эффектор. Мне понравилось. Советую посмотреть в его сторону))
Может и попробую. Настораживает, только то что у них 21 релиз, а на слуху так и не появился. Обычно хорошие либы быстро всплывают в разных статьях / видео / конфах.
Гооодится!
Я даже не припомню кейса , где бы нужно было в зависимость функцию передавать ,
Я обычно создаю функцию вне эффекта , а в эффекте вызываю ее передав в нее параметр categoryID например
Это значит, что ваш стек или ваши подходы к организации кода, полностью искореняют возможность такого кода. Например, мы сейчас пишем приложение используя mobX и там действительно нет никакой нужды делать такого рода конструкции, но в более простых pet проектах, я сталкивался с такой проблемой :)
@@it-sin9k Ну на сколько я понял, задача стоит в том , что при новом categoryId мы вызываем функцию , getBooks , но в этой функции мы используем пропс переданный в компонент , то есть , при входе на страницу , мы вызовем при монтировани страницы useEffect вызовет функцию и мы получим книги , указав зависимость categoryId мы получаем тот же результат , и при создании функции внутри хука при монтировании и при зависимости от категории , тот же результат
Да, абсолютно верно размышляете. Один лишь момент, который я уточнял, это то что многие могут использовать eslint плагин на проверку зависимостей. Поэтому я решил исходить из того, что вы используете eslint-plugin и он вас заставил бы добавить функцию как зависимость. Но функцию добавлять не хочется, так как выглядит слишком сложно тогда конструкция. И данное видео как раз является примером решения такой проблемы
@@it-sin9k теперь понял))
Geniously
5:28 а какой смысл выделять пямять чтобы дать функции название, если она сразу же вызывается? Можно просто создать самовызывающуюся анонимную стрелочную асинхронную функцию:
(async () => { await ... })()
Да можно и так сделать :)
Я использую чаще всего функцию с именем, потому что самовызывающиеся функции в коде почти никогда не встречаю в коде. Соответственно людям сложнее читать код.
@@it-sin9k, мб лучше просто передаваемую в useEffect функцию сделать асинхронной, а не в ней функцию создавать
@@gooseob Мб что то изменилось в последних версиях, но раньше React в консоль ошибку плевал, если ему асинхронную функцию передаешь
@@it-sin9k, а, понял, спасибо
@@it-sin9k, да, сейчас можно вроде. Я сначала объявлял асинхронную функцию, а потом передавал её в useEffect
вау-вау-вау!
хотелось бы увидеть развернутые ответы на вопросы, почему хуки названы хуками? почему это не часть жц функционального компонента
я расскажу свое видение из кода, который я прочел и обрывков фраз, которые я слушал на выступлениях на конференциях официальных от React Core team. "Hook" в переводе с английского языка звучит как "Крючок".
Допустим у нас есть компонент у которого есть useState(6). И как вы знаете эта цифра 6 будем доступна при первом рендере, втором или любом другом рендере, пока вы на одном из рендеров ее не перезапишите. Как перезапишите будет другое значение хранится в state. Хотя ваш компонент это всего лишь функция, а у функции как вы знаете не существует this. Где тогда хранится эта цифра 6?
Ответ прост, они сохраняют цепочку вызванных хуков условно в "глобальной переменной" и при новом рендере они крючком цепляются за туже "глобальную переменную".
Т.е. хук это не что иное как просто придуманная абстракция с именем, которое React разработчики посчитали наиболее успешным. Таким же образом они могли назвать хуки - например Packages / BusinessLogic/ КотВМешке / КонопляНаБатуте
@@it-sin9k я думал, что хуки подвязаны для каждого фибера, если они глобальным обьектом, как тогда реакт понимает, что у конкретной ноды - конкретные хуки?
Они хранятся у конкретной ноды, я поэтому и написал "условно"))
Я вот прямо сейчас расписываю новый выпуск и там как раз немного углубляюсь, про то как работают хуки) а пока рекомендую посмотреть это видео про исходники хуков - ua-cam.com/video/kcHEWut-DUA/v-deo.html
@@it-sin9k там тоже сказано, что хуки в глобал обьекте, меня как раз это и сбило с толку
по факту вот в переменную currentlyRenderingFiber присваивается текущая fiberNode.
И внутрь него в виде linkedList складываются все хуки
github.com/facebook/react/blob/v17.0.1/packages/react-reconciler/src/ReactFiberHooks.new.js#L557
А при повторном рендере из currentlyRenderingFiber.alternate достается linked list из прошлого рендера
github.com/facebook/react/blob/v17.0.1/packages/react-reconciler/src/ReactFiberHooks.new.js#L573
И начинается создание нового linked list. И в этой строке они берут данные из прошлого хука и сохраняют его в текущий хук
github.com/facebook/react/blob/v17.0.1/packages/react-reconciler/src/ReactFiberHooks.new.js#L606
не нужен await на 12 строке в бонусном примере?
а какой смысл нам ждать конца выполнения этой функции?
Более того наоборот, нужно скорее вернуть в return функцию, недожидаясь ответа от сервера, чтобы если deps изменяться, было что вызвать :)
@@it-sin9k ну чтобы у нас true не проставился в игнор еще до того как с сервера пришли данные. ощущение что данный код никогда не добавит книгу
хуки блочат рендер пока не будут завершены? await на сетевой запрос это уже браузер API, поэтому браузер может не блокировать основной поток нашим ожиданием промиса
более того замыкаться будет каждый вызов useEffect и это не спасет от двух изменений категории
но возможно я не понимаю хуки, я с ними еще не работал, вот знакомлюсь)
Я думаю вы упускаете несколько важный моментов:
- в return мы возвращаем функция, вызов которого откладывается до изменения dependencies, т.е. isIgnoreResponse не изменяется до того как зависимости не изменятся
- абсолютно для каждого вызова функции переданной в useEffect создается своя переменная isIgnoreResponse.
Я вас точно уверяю, что код рабочий, вам стоит попробовать написать и поиграться с ним, чтобы вникнуть :)
несмотря на то что автор не ответил на предыдущий мой комментарий все же добавлю. если функция которая загружает не из пары строк состоит и она используется так же и в другом месте, то пихать ее в эффект совсем нехорошо, поскольку придется ее и в другом месте дублирлвать. получается дублирование кода и загромождение эффекта. не все так однозначно.
сорри, что пропустил другой ваш вопрос.
В данном вопросе вроде как размер функции не имеет значения. Вместо api.getBooks() будет какая то кастомная функция, но суть вроде как не меняется
const books = getBooks(...) // some custom function
setBooks(books)
@@it-sin9k спасибо за пояснения
А если не указывать loadBooks как зависимость и не идти на поводу у eslint? Тогда никакого лишнего кода, читаемость лучше чем с калбеками, а то что loadBooks каждый рендер создается пофиг, это вряд ли станет узким местом в программе
Это будет вполне себе работать. И читабельность будет терпимой. Только придется смириться с несколькими вещами:
1) отказаться от eslint правила следящего за зависимостями
2) смириться с тем что вы создаете функцию до того как контент отрисовывается в браузере, а не прямо перед ее использованием (офк это экономия на спичках, не сильно тянет как весомый аргумент)
А так да вполне рабочий вариант, я бы даже сказал, лучше чем с useCallback
@@it-sin9k можно даже отмену запроса в эффекте реализовать, создать объект с полем отмены присваивания и просто передавать в функцию loadData, а в функции сброса менять это поле, useRef на коленках :)
я думаю, что многие к такому подходу пришли без чтение документации, через практику
7:33 а нельзя ли использовать abort.controller?
Вполне себе можно :)
7:10
пам пам, и 3 пришел раньше чем 2, ибо асинхронное общение с сервером, и первый запрос не гарантирует первый ответ, а ты потом радуйся жизни, ловя плавающий баг
ну вроде в решении которое идет дальше, учтен этот момент :)
@@it-sin9k дальше да, я к тому что в этом моменте не моргание самая большая проблема
@@vargvarg7922 согласен)
хера ты жесткий)
norm
Даже не знала, что некоторые люди пишут первым способом. Интересно)
Честно говоря, когда хуки начинал осваивать, я сам так писал) и уже когда обжился с хуками, почитал документацию, уже начал писать по новому)
@@it-sin9k тоже писал первым способом, сейчас перепишу часть прода и задеплоюсь :) спасибо
@@ДмитрийИванов-з8з2м Рад, что данное видео оказалось полезным)
+
Дока не пропагандирует подход, а предоставляет максимально простой и понятный код, для более быстрого и легкого понимания механизма и принципа работы.
Самое рациональное решение - вызывать запрос в санке или саге. В хуке useEffect будет максимально понятное - вызов экшена и передача id в него и они же в зависимостях. Ты пропагандируешь лишнюю связанность кода. Компонент не должен знать о запросе.
Так код, который я предоставил, это пример из реакт документации) тогда получается из этих слова "Ты пропагандируешь лишнюю связанность кода", не я пропогандирую, а документация все таки))
Ну а если серьезно, то не одним редаксом едины. Сейчас уже не первый проект вижу тенденцию, что люди отказываются от того, чтобы всю асинхронщину совать в thunk / saga. Их мотивация заключается в том, что если ты используешь thunk, тогда тебе надо хранить информацию в redux. Если хранишь информацию в redux, а ты ее не планируешь глобально использовать, по разным причинам, например быстрой потери актуальности информации. Тогда тебе приходится еще чистить redux store, после анмаунта компонента. И люди решили, а зачем было вмешивать редакс в этот флоу? нельзя было просто в хуке сделать запрос показать лодинг и стейт сам очиститься после анмаунта? Особенно это актуально в RN проектах. Где тьма экранов, с мелкими запросами, и надо все равно приходится каждый раз перезапрашивать актуальные данные.
В итоге, я все чаще вижу проекты, где люди прогоняют через redux, только те запросы и данные, которые действительно нужно хранить глобально. А если тебе не нужно хранить глобально, тогда вот такое написание кастомного хука часто можно встретить в проекте.
paste.ubuntu.com/p/83zssmRhPR/
Более того, если писать сейчас на mobX проект. Скорей всего будете использовать mobx-react-lite, у которого весь код будет в кастомных хуках обернутых внутри в useLocalObservable)
Поэтому если, вы решили использовать redux по максимуму в своем проекте, а реакт только для отрисовки, это не значит, что ваш подход лучший и все должны его использовать. Это лишь один из возможных вариантов написания сайта.
Более того, я писал раньше код, так как вы предлагаете и продвигал в массы, что при таком подходе все однообразно просто и понятно. Но на дистанции. Сначала я отказался от Саги, т.к. она начала давать больше сложностей, чем пользы. Потом от redux-form, т.к. сам создатель либы от нее отказался, все по этим же причинам, чтобы не сотрясать лишний раз редакс. И в итоге отказался от хранения всех данных в redux)
Просто делюсь своим опытом)
от твоего сообщения веет Димычем) к счастью, его подход - не панацея)
@@it-sin9k по-моему, тех, кто хранит все данные в глобальном сторе нужно принудительно лечить (за редким исключением, когда это действительно нужно).
А глобальное хранилище не должно знать о данных, которые нужны только в рамках компонента.
Компонент должен звать какой-то слой отвечающий за запрос данных, а лучше ещё промежуточный слой, который отвечает за логику выполняя роль application из DDD.
Но все равно, он будет асинхронным, поэтому нету смысла усложнять пример... как и использовать Redux для запросов.
Как раз Redux для запросов и даёт лишнюю связанность кода, а если писать на чемоданчиком э человеческом TS (в крайнем случае JS), то потом код можно реально переиспользовать.
700 likes
Спасибо!
хотя как и под любым из найденных мною видео куча восторженных комментариев, особой сути рассказанного не много. зачем все лепить в эффект? если на конкретном примете где пара строк кода, то да. но глядя на это народ станет же все так лепить по десятку выполняемых задач в одном эффекте, когда гораздо лучше вызвать в нем отдельные функции каждая из которых занимается своим делом. в итоге в попытке оптимизировать, получается просто укрупнение. да и что сэкономлено непонятно. ни скорость выполнения не сравнили ни расход памяти. очень дорогих буков меньше? так можно было и еще сократить. функции короче называть можно, как вебпак сразу по одной букве. если и показываете что это хорошо, то уж сравнительные данные не помешают, а иначе весь этот подход к хорошему не доведет. я не сомневаюсь что Вы понимаете что делаете, а вот поймет ли смысл посмотревший это новичок, коих тут полно и которые как на второе пришествие на автора смотрят. а при любом применении любой оптимизации в первую очередь надо понимать для чего и стоит ли оно того. а так же последствия.
Я сходу не понял, нафига создавать функцию вместе того, чтобы потом ее отдельно вызывать.
А потом понял, на какие костыли не приходится идти, если не используешь RxJS 🤣
7:40 isIgnoreResponse sounds unnatural.
I'd better call it shouldIgnoreResponse.
thanks!
Я создаю внутри useEffect самовызывающуюся функцию (async () => {...})(). В этом случае мне не приходится как то её называть и вызывать после создания. Нам ведь функция нужна для того , что бы сделать её асинхронной. Не знаю правда на сколько читабильно
Да, вопросик есть только в читабельности :)
sin9k, 9000 грехов! 9 грех это ок!
Можно и не использовать isIgnoreResponse. А просто прервать запрос. А промис в исключение улетит
офигеть какой контент! такого еще не видела
++ за пояснения с графом
Спасибо :) И добро пожаловать!)