⚛️ неочевидный react
Похоже, далеко не все понимают как работает React, в частности: контекст, рендер, как всплывают события и почему происходят ремаунты, казалось бы в тех местах, где их не должно быть. Я конечно не претендую на реакт-эксперта, но хотел бы прояснить кое-какие моменты, которые не описаны в доке, или упоминаются как-то вскользь. Будет много ссылок на демки где можно поиграться, посмотреть логи и подробнее разобраться.
- Начнем с самого простого - контекста. Контекст нужен что бы доставить данные вглубь React дерева, при это избегая props-drillingа, пробрасывания данных через кучу родителей к дочерним. В целом в доке все отлично расписано, но многие не обращают внимание на один важный момент: все потребители контекста, неважно, это
https://codesandbox.io/s/object-in-the-context-nh1ud?file=/src/App.tsx в этом примере на каждый рендер провайдера создается новый объект, что вызывает перерасчет всех потребителей, в больших приложениях это может привести к большому даунгрейду перфа. Фикситься достаточно просто, использованием
- Как я понял, многие предполагают что компонент монтируются (или по крайней мере его рендер вызывается) в момент создание элемента
https://codesandbox.io/s/react-render-8zm5d?file=/src/App.tsx:1059-1070 в примере выше
1) компонент использует
2) новый элемент не был создан в момент ререндера родителя - это можно сделать различными способами, в примере по ссылке это делается через создание элементов за пределами рендер метода. Но того же эффекта можно добиться положив элемент в
Продолжение в первом коменте...
Читать в ноушен: https://bit.ly/3jwrFYY
#react
Похоже, далеко не все понимают как работает React, в частности: контекст, рендер, как всплывают события и почему происходят ремаунты, казалось бы в тех местах, где их не должно быть. Я конечно не претендую на реакт-эксперта, но хотел бы прояснить кое-какие моменты, которые не описаны в доке, или упоминаются как-то вскользь. Будет много ссылок на демки где можно поиграться, посмотреть логи и подробнее разобраться.
- Начнем с самого простого - контекста. Контекст нужен что бы доставить данные вглубь React дерева, при это избегая props-drillingа, пробрасывания данных через кучу родителей к дочерним. В целом в доке все отлично расписано, но многие не обращают внимание на один важный момент: все потребители контекста, неважно, это
Context.Consumer
или React.useContext(Context)
, будут перерисовываться (т.е. вызван render метод, а не обновлен DOM) каждый раз когда значение контекста меняется. Это значит что использовать объекты, без предварительного кэширования, в контексте - плохая идея, т.к. все потребители будут перерисовываться на каждый рендер провайдера, даже если данные в этом объекте никогда не меняются.
<Context.Provider value={{ value: 20 }}>{children}</Context.Provider>
https://codesandbox.io/s/object-in-the-context-nh1ud?file=/src/App.tsx в этом примере на каждый рендер провайдера создается новый объект, что вызывает перерасчет всех потребителей, в больших приложениях это может привести к большому даунгрейду перфа. Фикситься достаточно просто, использованием
useMemo
или useRef
, в зависимости от того, меняются ли значения в объекте.- Как я понял, многие предполагают что компонент монтируются (или по крайней мере его рендер вызывается) в момент создание элемента
const child = <Child />
, даже если элемент не был использован в ретурне рендера родителя. На самом деле это не так, компонент не монтируется и даже его рендер не вызывается, если элемента этого компонента нет в React дереве, другими словами если компонент не был использован в ретурне рендера родителя. Отсюда вытекает еще одна неочевидность: компонент монтируются столько раз, сколько раз его элемент появился в React дереве.
const child = <Child name="renderChild" />;
const unusedChild = <Child name="unusedChild" />;
return (
<>
{child}
{child}
{child}
{false && unusedChild}
</>
)
https://codesandbox.io/s/react-render-8zm5d?file=/src/App.tsx:1059-1070 в примере выше
Child
с названием renderChild монтируются 3 раза, т.к. 3 элемента используется в дереве, а вот unusedChild вообще не монтируются да и рендер для него тоже не вызовется, поскольку его нет в дереве. Все тоже касается и последующих ререндеров, но здесь есть 2 НО, когда ререндера может не произойти: 1) компонент использует
React.iss.onemo
- пропсы не поменялись, ререндер не произошел2) новый элемент не был создан в момент ререндера родителя - это можно сделать различными способами, в примере по ссылке это делается через создание элементов за пределами рендер метода. Но того же эффекта можно добиться положив элемент в
useRef
или useMemo
. Чет мне кажется, что работает оно так-же как и React.iss.onemo
только без дополнительных проверок пропсов в момент рендера, а просто сравнивается сслыка элемента - я не проверял в сорцах, просто предположение.Продолжение в первом коменте...
Читать в ноушен: https://bit.ly/3jwrFYY
#react
👍1
🦾 local env на стиройдах
Как я уже упоминал несколько раз, весь наш бэкенд построен на микросервисах. Есть сервисы-апишки - общаются с фронтом, сервисы-рантаймы - ранают скилы/экшены/проекты и интегрируются с alexa/google assistant/voiceflow(наш кастомный ассистент)/прочими платформами, ну и куча других сервисов с джобами, nlp/nlu, доступа к данным и тд. На каждую платформу приходится как минимум по 2 сервиса (апишка и рантайм), следовательно кол-во сервисов растет с добавлением новых платформ в проект. Все это работает прекрасно и позволяет нам скейлится по мере необходимости и расширять платформы не боясь, что интеграция с существующей платформой отвалится.
Но во всей этой красоте есть один большой нюанс - local env.
- Во-первых, засетапить такой зоопарк локально достаточно сложно:
- 3 базы данных
- куча сервисов
- практически все сервисы общаются с сервисами доступа к данным и кэшем
- сервисы апишки/рантаймы для платформ (alexa/google/...) общаются с апишкой/рантаймом voiceflow (что бы конвертнуть проект платформы в проект voiceflow или запустить проект у нас в туле, без коммуникации с платформой)
- фронт общается с апишками-платформ, дженерик апишкой, ну и парочку других сервисов
Другими словами сервисы и фронт между собой связанны, и в env-переменных нужно ссылаться друг на друга. Новые члены команды обычно страдали первые пару дней, что бы все это запустить...
- Во вторых, наш фронт сам по себе достаточно тяжелый и dev-server хавает много ресурсов. А если запустить весь этот зоопарк сервисов, то macbook с 16 гигами не справляется и разрабатывать практически невозможно, и не важно что сервисы на ноде и сами по себе не ресурсоёмкие, но их много...
- Ну и в третьих, не совсем относится к local env, но развернуть тестовый env в облаке(где одни сервисы юзают код из своих мастер веток, а другие - из кастомных) - геморно и требует совместной работы с девопсами. Поэтому мы юзали костыль в виде нескольких staging (staging-a, staging-b, etc) веток в каждой репе, и пушили туда свои ветки и проверяли в облаке 😂.
Около годна назад наша инфра-тима решила помочь нам с этим и написала cli-тулу, которая решала первую и третью проблемы, а так же частично вторую. Эта тула может одной командой склонить все наши репы(сервисы, фронт, базы, либы). Создать локальные env файлы и проставить нужные env-переменные, что бы залинковать сервисы и быза. Ну и естественно запустить весь этот зоопарк локально. Есть и набор снипетов, что бы ранать только часть сервисов, например только те сервисы которые необходимы для работы фронта, что позволяло экономить ресурсы. Тула также позволяет одной командой создать env в облаке, все сервисы разворачиваются и ты получаешь урл на новый env. По дефолту сервисы юзают мастер ветки, но есть команда, что бы переключить любой сервис на нужную ветку. Под капотом тула написана на Go, юзает докер и кубик.
В целом на этом можно было и закончить, но проблема с ресурсами не была решена для всех. Некоторым ребятам в команде (в основном бэкендерам) нужно ранать все сервисы, ибо большинство новых фич затрагивают все платформы. Да и к тому же сервисов становится все больше, докер хавает все больше, комп греется все больше, кернел тормозит процесс все больше, в итоге через пару часов активной разработки летом я вырубал мак и клал его в морозилку, что бы усмирить кернел таск, как вам лайфхак?
Продолжение в первом коменте...
Читать в ноушен: https://bit.ly/3Dq9XhX
#tools #longread
Как я уже упоминал несколько раз, весь наш бэкенд построен на микросервисах. Есть сервисы-апишки - общаются с фронтом, сервисы-рантаймы - ранают скилы/экшены/проекты и интегрируются с alexa/google assistant/voiceflow(наш кастомный ассистент)/прочими платформами, ну и куча других сервисов с джобами, nlp/nlu, доступа к данным и тд. На каждую платформу приходится как минимум по 2 сервиса (апишка и рантайм), следовательно кол-во сервисов растет с добавлением новых платформ в проект. Все это работает прекрасно и позволяет нам скейлится по мере необходимости и расширять платформы не боясь, что интеграция с существующей платформой отвалится.
Но во всей этой красоте есть один большой нюанс - local env.
- Во-первых, засетапить такой зоопарк локально достаточно сложно:
- 3 базы данных
- куча сервисов
- практически все сервисы общаются с сервисами доступа к данным и кэшем
- сервисы апишки/рантаймы для платформ (alexa/google/...) общаются с апишкой/рантаймом voiceflow (что бы конвертнуть проект платформы в проект voiceflow или запустить проект у нас в туле, без коммуникации с платформой)
- фронт общается с апишками-платформ, дженерик апишкой, ну и парочку других сервисов
Другими словами сервисы и фронт между собой связанны, и в env-переменных нужно ссылаться друг на друга. Новые члены команды обычно страдали первые пару дней, что бы все это запустить...
- Во вторых, наш фронт сам по себе достаточно тяжелый и dev-server хавает много ресурсов. А если запустить весь этот зоопарк сервисов, то macbook с 16 гигами не справляется и разрабатывать практически невозможно, и не важно что сервисы на ноде и сами по себе не ресурсоёмкие, но их много...
- Ну и в третьих, не совсем относится к local env, но развернуть тестовый env в облаке(где одни сервисы юзают код из своих мастер веток, а другие - из кастомных) - геморно и требует совместной работы с девопсами. Поэтому мы юзали костыль в виде нескольких staging (staging-a, staging-b, etc) веток в каждой репе, и пушили туда свои ветки и проверяли в облаке 😂.
Около годна назад наша инфра-тима решила помочь нам с этим и написала cli-тулу, которая решала первую и третью проблемы, а так же частично вторую. Эта тула может одной командой склонить все наши репы(сервисы, фронт, базы, либы). Создать локальные env файлы и проставить нужные env-переменные, что бы залинковать сервисы и быза. Ну и естественно запустить весь этот зоопарк локально. Есть и набор снипетов, что бы ранать только часть сервисов, например только те сервисы которые необходимы для работы фронта, что позволяло экономить ресурсы. Тула также позволяет одной командой создать env в облаке, все сервисы разворачиваются и ты получаешь урл на новый env. По дефолту сервисы юзают мастер ветки, но есть команда, что бы переключить любой сервис на нужную ветку. Под капотом тула написана на Go, юзает докер и кубик.
В целом на этом можно было и закончить, но проблема с ресурсами не была решена для всех. Некоторым ребятам в команде (в основном бэкендерам) нужно ранать все сервисы, ибо большинство новых фич затрагивают все платформы. Да и к тому же сервисов становится все больше, докер хавает все больше, комп греется все больше, кернел тормозит процесс все больше, в итоге через пару часов активной разработки летом я вырубал мак и клал его в морозилку, что бы усмирить кернел таск, как вам лайфхак?
Продолжение в первом коменте...
Читать в ноушен: https://bit.ly/3Dq9XhX
#tools #longread