Мы забываем основы фронтенд-разработки

Я всегда считал, что все не так уж плохо, если есть умелые руки, которые могут делать практически все. Однако наблюдение за ситуацией, сложившейся в последнее время во фронтенд-разработке, заставило меня изменить мнение. Похоже, что, увлекаясь бесконечными трендами, парадигмами и новыми технологиями, мы стали пренебрегать основами фронтенда.

Попробую объяснить это на примере фрагментов кода из последних проектов моей команды.

Бесконечное усложнение

В первом фрагменте имеется самый простой компонент Card, у которого есть опциональное свойство header. Если это свойство существует, рендерим его внутри обертки div с определенным классом.

const Card = ({ children, header }) => {
return (
<div className="card">
{header && <div className="card__header">{header}</div>}
{children}
</div>
);
};

В простых вариантах все работает просто замечательно. В этом случае заголовок <Card /> не отображается, а вот в другом случае имеем <Card header={"I am header"} />. Проблемы возникают, когда контент заголовка является динамическим и может возвращать фактический контент или null  —  <Card header={<CardHeader />} />. Условие {header && <div />} не может его обнаружить и отрендерит пустой div.

Один разработчик попытался решить эту проблему. Он подумал: “Можно ведь проверить контент div и скрыть его, если он пуст”. Вот примерный код, который он написал:

const Card = ({ children, header }) => {
const headerRef = useRef();

useEffect(() => {
const hasContent = headerRef.current?.childNodes.length > 0;
headerRef.current.style.display = hasContent ? "block" : "none";
});

return (
<div className="card">
{header && (
<div ref={headerRef} className="card__header">
{header}
</div>
)}
{children}
</div>
);
};

В процессе проверки другой разработчик заметил, что этот код работает только при первоначальном процессе рендеринга. При асинхронном обновлении нижнего колонтитула useEffect не будет вызван. После долгих размышлений разработчики решили воспользоваться MutationObserver.

Во время обсуждения они также обратились за советом ко мне. Честно говоря, было очень забавно представить им мой вариант. Для решения этой проблемы достаточно было просто использовать обычный CSS.

.card__header:empty {
display: none;
}

Разработчики настолько привыкли усложнять задачи, что даже не вспомнили о базовых возможностях CSS.

Ошибки 1993 года

В предыдущем проекте у нас был виджет боковой панели, который должен был растягиваться на всю высоту, но не перекрывать заголовок и нижний колонтитул. Примерная формула выглядит следующим образом: 100% - headerHeight - footerHeight.

Решение отлично работало на всех страницах, кроме одной. На этой странице footerHeight почему-то был равен 0. Разработчик, который обнаружил эту ошибку, копнул глубже и понял, что document.querySelector('footer') возвращает null, но нижний колонтитул все равно отображается на странице. Как вы думаете, что он сделал? Да, снова использовал MutationObserver.

Мне это показалось странным, и я предложил альтернативное решение  —  достаточно было просто поменять местами пару строк кода.

<html>
<head></head>
<body>
<header></header>
<main id="root"></main>
<script src="index.js"></script>
<footer></footer>
</body>
</html>

Каким-то образом <script /> оказался на странице перед нижним колонтитулом. <script /> вызывается синхронно, а нижний колонтитул в этот момент не существует, поэтому измерить его высоту невозможно. Я просто поменял эти строки местами, и все стало работать как надо.

В наше время разработчики слишком полагаются на современные инструменты, такие как webpack-plugin и т. д. Поэтому, когда дело доходит до самостоятельного написания HTML, сразу же сдаются. Хотя что тут сложного?

Корень всех зол

React-хуки  —  это одновременно и лучшее, и худшее, что есть в React. С одной стороны, они обеспечивают гибкость и элегантный способ работы с состоянием, с другой  —  резко повышают сложность кода и умножают ошибки.

Казалось бы, нет ничего сложного в том, чтобы внимательно прочитать документацию и понять, как правильно все использовать. Однако некоторые разработчики пропускают этот закономерный этап и начинают использовать хуки, не имея четкого представления об их назначении. В частности, когда дело доходит до оптимизации, прибегают к пресловутым useMemo и useCallback. Теперь каждый разработчик оптимизирует все приложение без явной причины.

Посмотрим на эту “критически важную” оптимизацию. Приведенный ниже фрагмент  —  не выдуманный код, написанный специально для этой статьи. Он взят из реального проекта.

const loaded = useMemo(() => {
return submitted && !loading && !error;
}, [submitted, error, loading]);
}

После такого “улучшения” производительность приложения просто “взлетела до небес”! Как вы понимаете, подобная оптимизация совершенно бесполезна и даже немного вредит первой загрузке приложения. Честно говоря, я до сих пор не понимаю, с какой целью был написан приведенный выше код.

Проще принимать все как данность, ни во что не углубляясь. Но разве так трудно провести собственное мини-исследование?

Несколько важных советов

Ситуация выглядит довольно печально. Во всей этой мешанине новых технологий и подходов разработчики начинают забывать основы фронтенда и утрачивают способность к критическому мышлению.

Однако, на мой взгляд, решить эту проблему не так уж и сложно. Достаточно следовать простым, но важным рекомендациям.

  • Разберитесь в ванильном JavaScript. Имея под ногами прочный фундамент, легче обнаружить реальные причины ошибок и быстро их исправить.
  • Глубоко изучите HTML и CSS. Вы откроете для себя множество полезных свойств, селекторов и других компонентов, которые могут заменить тонны JS-кода.
  • Развивайте навыки критического мышления. Руководитель команды наверняка обучил вас лучшим практикам и принципам. Однако, слепо следуя им, можно выбрать неправильное направление. Вместо этого старайтесь понять, почему что-то происходит именно так, а не иначе.
  • Помните о SOLID, YAGNI, KISS и других принципах программирования. Если простая задача оказывается кошмаром с запутанным решением  —  просто остановитесь и переосмыслите ее, посмотрев на исходные данные под другим углом. Возможно, вы слишком углубились в одно решение и забыли о чем-то очевидном.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Pavel Pogosov: We Forgot Frontend Basics

Предыдущая статьяКак исследовать и визуализировать данные МО для обнаружения объектов на изображениях
Следующая статьяЧто такое Recover в Golang?