Об основных ошибках junior-разработчиков, использующих React. На чем сыпятся джуны, и как с этим жить. Перевод статьи «Mistakes Junior React Developers Make» от специалиста Frontend практики «Рексофт».
![](https://habrastorage.org/r/w780q1/webt/-4/ms/qa/-4msqagos-pbjqn4rze85xax-mo.jpeg)
Такого рода ошибка встречается особенно часто среди разработчиков, которые только пересели с jQuery.
![](https://habrastorage.org/r/w780q1/webt/ez/je/da/ezjedayuildce37foqgj6gnycom.jpeg)
В React мы должны избегать прямых взаимодействий с DOM. Вместо того чтобы получать ссылку на DOM узел и добавлять к нему класс напрямую, следует изменить состояние в самом компоненте, исходя из которого и будет добавлен класс к элементу.
Что же такого плохого в прямых манипуляциях DOM?
Любое веб-приложение на самом деле строится на состоянии и его управлении. Есть прямая зависимость между сложностью ПО и состоянием, которое его описывает. Если ваше приложение совмещает состояния DOM и React, то сложность его поддержки вырастет очень быстро.
![](https://habrastorage.org/r/w780q1/webt/yi/s7/bb/yis7bbfx6kmpefj47mtk4qc0ec4.jpeg)
Обратим внимание на то, как мы используем React состояние для обновления атрибута className в нашем компоненте, и, как следствие, мы избавились от document.querySelector. Отлично!
Новички в разработке часто пишут такой код, когда работают с событиями. Возьмем, например, простой React компонент, который делает… что-то, когда пользователь нажмет пробел.
![](https://habrastorage.org/r/w780q1/webt/ig/gh/j6/igghj6ogmfxqz_fayor2_hk5h-0.jpeg)
Заметили, как мы добавили слушатель события, но не позаботились о том, чтобы удалить его в конце?
Это может привести к утечкам памяти и трудноуловимым проблемам в будущем. Лучшим решением считается удаление подписчиков перед тем, как наш компонент будет удален из DOM.
Взглянем на решение ниже:
![](https://habrastorage.org/r/w780q1/webt/xd/ji/du/xdjidulcxet783tzejtdw0iby64.jpeg)
Если бы мне давали по рублю за каждый проект, который я просмотрел и где единственным тестом был тот, что является по умолчанию в create-react-app, я не писал бы эту статью. А, наверное, потягивал сейчас дайкири где-нибудь на пляже.
Что же такого в тестировании, что так пугает джунов? Я думаю, причина заключается в нетривиальности тестирования компонентов, особенно при условии их постоянного развития и роста комплексности. Часто вижу, как младшие программисты пишут юнит-тесты для каких-то определенных чистых функций, но терпят неудачу в случае, когда нужно написать интеграционный тест для целого компонента.
Может быть, заглушки сбивают их с толку? Или они испытывают сложности с тем, что следует тестировать и что нет?
Давайте взглянем на компонент, который я только что написал. Это очень простая форма входа, где пользователь должен ввести свой логин и пароль. Когда последний подтверждает введенную информацию, мы делаем вызов API и в случае, если ответ положительный, направляем клиента на другую страницу.
![](https://habrastorage.org/r/w780q1/webt/x9/z7/x0/x9z7x0qgsvdy9yikfdcofrwthdi.jpeg)
Первым делом давайте взглянем, каким образом наш пользователь будет взаимодействовать с ней.
Пользователь вводит свои данные.
Пользователь нажимает на кнопку подтверждения.
Пользователь перенаправляется на страничку «home».
Это и есть все то, что нам нужно протестировать.
Ниже я написал один из тест-кейсов для данного компонента. Можете ли вы предложить какие-нибудь еще сценарии, которые было бы полезно протестировать?
![](https://habrastorage.org/r/w780q1/webt/ka/e6/s5/kae6s5zuwypdocz2nml-_0bim2y.jpeg)
Указанный пример с тестированием не является рекомендуемым ввиду сильной связи со слоем представления и деталями реализации.
Для слоя представления можно подобрать более легковесную, с точки зрения разработки, альтернативу в виде визуальных тестов через снимки, это не покроет все потребности, но закроет большинство рисков связанных со стилизацией.
Завязывая тесты на детали реализации мы обрекаем себя на нужду их постоянного переписывания в случае когда эта реализация поменяется (но поведение останется прежним), тем самым мы увеличиваем затраты на разработку. Такие тесты, также как следствие, являются довольно медленными т. к. эмулируют DOM окружение для работы библиотек.
Интеграционные тесты обозначают тесты, которые проверяют поведение некоторого множества связанных между собой модулей, однако это вовсе не значит что в эту связку должны быть включены сторонние библиотеки, которые хоть и предлагают стабильное АПИ, но требуют эмуляции окружения браузера что негативно влияет на скорость выполнения всех проверок. Вместо таких библиотек обычно используются моковые объекты, эмулирующие их поведение, но не завязанные на окружение.
Если все же требуется некоторое средство проверки таких библиотек, например для снижения рисков при переходах на новые версии, в таком случае решением будет являться специальный набор тестов, которые обычно называются приемочными. Перед их написанием стоит составить четкий набор инвариантов, пре условий и пост условий, на которые опирается наше приложение при использовании библиотеки. И заключить сформированные поведенческие контракты в виде тестов. Через эти тесты полезно прогонять как реальные библиотеки, так и моковые объекты, которые эмулируют поведение последних.
Если подытожить, то, хорошими тестами являются те, что обеспечивают полное покрытие поведений (поведений, а не реализаций), легко читаются (тесты должны читаться лучше обычного кода), быстро выполняются (медленные тесты негативно сказываются на желании частого рефакторинга) и, наконец, те что завязаны на поведение, а не реализацию.
Некоторые из младших разработчиков, с которыми я работал, знали, как использовать, но не понимали, как работает Webpack. Они использовали только лишь с основной кодовой базой проекта и считали, что все остальное «работает просто потому что». Они не копали глубже, не выясняли, как именно CSS и ES6, который они пишут, трансформируется и объединяется в то, что в конечном итоге используется клиентским браузером.
Я рекомендую каждому React-разработчику выделить время и построить простой шаблонный проект. Вместо того, чтобы каждый раз полагаться на create-react-app и NextJS, разберитесь, как современные инструменты сборки JavaScript работают вместе. Это улучшит ваше понимание своей работы и, как следствие, сделает вас более эффективным разработчиком, особенно при решении проблем со сборкой.
Оригинал: medium.com/frontend-digest/mistakes-junior-react-developers-make-c546b1af187d
![](https://habrastorage.org/webt/-4/ms/qa/-4msqagos-pbjqn4rze85xax-mo.jpeg)
Прямые манипуляции с DOM
Такого рода ошибка встречается особенно часто среди разработчиков, которые только пересели с jQuery.
Писали ли вы такой код?
![](https://habrastorage.org/webt/ez/je/da/ezjedayuildce37foqgj6gnycom.jpeg)
В чем же проблема?
В React мы должны избегать прямых взаимодействий с DOM. Вместо того чтобы получать ссылку на DOM узел и добавлять к нему класс напрямую, следует изменить состояние в самом компоненте, исходя из которого и будет добавлен класс к элементу.
Что же такого плохого в прямых манипуляциях DOM?
Любое веб-приложение на самом деле строится на состоянии и его управлении. Есть прямая зависимость между сложностью ПО и состоянием, которое его описывает. Если ваше приложение совмещает состояния DOM и React, то сложность его поддержки вырастет очень быстро.
Возможное решение
![](https://habrastorage.org/webt/yi/s7/bb/yis7bbfx6kmpefj47mtk4qc0ec4.jpeg)
Обратим внимание на то, как мы используем React состояние для обновления атрибута className в нашем компоненте, и, как следствие, мы избавились от document.querySelector. Отлично!
Не следить за ресурсами
Новички в разработке часто пишут такой код, когда работают с событиями. Возьмем, например, простой React компонент, который делает… что-то, когда пользователь нажмет пробел.
![](https://habrastorage.org/webt/ig/gh/j6/igghj6ogmfxqz_fayor2_hk5h-0.jpeg)
Заметили, как мы добавили слушатель события, но не позаботились о том, чтобы удалить его в конце?
Это может привести к утечкам памяти и трудноуловимым проблемам в будущем. Лучшим решением считается удаление подписчиков перед тем, как наш компонент будет удален из DOM.
Взглянем на решение ниже:
![](https://habrastorage.org/webt/xd/ji/du/xdjidulcxet783tzejtdw0iby64.jpeg)
Отказ от тестов (или их недостаточное количество)
Если бы мне давали по рублю за каждый проект, который я просмотрел и где единственным тестом был тот, что является по умолчанию в create-react-app, я не писал бы эту статью. А, наверное, потягивал сейчас дайкири где-нибудь на пляже.
Что же такого в тестировании, что так пугает джунов? Я думаю, причина заключается в нетривиальности тестирования компонентов, особенно при условии их постоянного развития и роста комплексности. Часто вижу, как младшие программисты пишут юнит-тесты для каких-то определенных чистых функций, но терпят неудачу в случае, когда нужно написать интеграционный тест для целого компонента.
Может быть, заглушки сбивают их с толку? Или они испытывают сложности с тем, что следует тестировать и что нет?
Давайте взглянем на компонент, который я только что написал. Это очень простая форма входа, где пользователь должен ввести свой логин и пароль. Когда последний подтверждает введенную информацию, мы делаем вызов API и в случае, если ответ положительный, направляем клиента на другую страницу.
![](https://habrastorage.org/webt/x9/z7/x0/x9z7x0qgsvdy9yikfdcofrwthdi.jpeg)
Так как же протестировать данную форму?
Первым делом давайте взглянем, каким образом наш пользователь будет взаимодействовать с ней.
Пользователь вводит свои данные.
Пользователь нажимает на кнопку подтверждения.
Пользователь перенаправляется на страничку «home».
Это и есть все то, что нам нужно протестировать.
Ниже я написал один из тест-кейсов для данного компонента. Можете ли вы предложить какие-нибудь еще сценарии, которые было бы полезно протестировать?
![](https://habrastorage.org/webt/ka/e6/s5/kae6s5zuwypdocz2nml-_0bim2y.jpeg)
Мнение специалиста Frontend практики «Рексофт»
Указанный пример с тестированием не является рекомендуемым ввиду сильной связи со слоем представления и деталями реализации.
Для слоя представления можно подобрать более легковесную, с точки зрения разработки, альтернативу в виде визуальных тестов через снимки, это не покроет все потребности, но закроет большинство рисков связанных со стилизацией.
Завязывая тесты на детали реализации мы обрекаем себя на нужду их постоянного переписывания в случае когда эта реализация поменяется (но поведение останется прежним), тем самым мы увеличиваем затраты на разработку. Такие тесты, также как следствие, являются довольно медленными т. к. эмулируют DOM окружение для работы библиотек.
Интеграционные тесты обозначают тесты, которые проверяют поведение некоторого множества связанных между собой модулей, однако это вовсе не значит что в эту связку должны быть включены сторонние библиотеки, которые хоть и предлагают стабильное АПИ, но требуют эмуляции окружения браузера что негативно влияет на скорость выполнения всех проверок. Вместо таких библиотек обычно используются моковые объекты, эмулирующие их поведение, но не завязанные на окружение.
Если все же требуется некоторое средство проверки таких библиотек, например для снижения рисков при переходах на новые версии, в таком случае решением будет являться специальный набор тестов, которые обычно называются приемочными. Перед их написанием стоит составить четкий набор инвариантов, пре условий и пост условий, на которые опирается наше приложение при использовании библиотеки. И заключить сформированные поведенческие контракты в виде тестов. Через эти тесты полезно прогонять как реальные библиотеки, так и моковые объекты, которые эмулируют поведение последних.
Если подытожить, то, хорошими тестами являются те, что обеспечивают полное покрытие поведений (поведений, а не реализаций), легко читаются (тесты должны читаться лучше обычного кода), быстро выполняются (медленные тесты негативно сказываются на желании частого рефакторинга) и, наконец, те что завязаны на поведение, а не реализацию.
Непонимание Webpack
Некоторые из младших разработчиков, с которыми я работал, знали, как использовать, но не понимали, как работает Webpack. Они использовали только лишь с основной кодовой базой проекта и считали, что все остальное «работает просто потому что». Они не копали глубже, не выясняли, как именно CSS и ES6, который они пишут, трансформируется и объединяется в то, что в конечном итоге используется клиентским браузером.
Я рекомендую каждому React-разработчику выделить время и построить простой шаблонный проект. Вместо того, чтобы каждый раз полагаться на create-react-app и NextJS, разберитесь, как современные инструменты сборки JavaScript работают вместе. Это улучшит ваше понимание своей работы и, как следствие, сделает вас более эффективным разработчиком, особенно при решении проблем со сборкой.
Оригинал: medium.com/frontend-digest/mistakes-junior-react-developers-make-c546b1af187d