Главная » Статьи » Как писать более читаемый код React

Как писать более читаемый код React

Как писать более читаемый код React

От автора: один из важнейших аспектов кода — его читабельность. Легко читаемый код — это результат качественного написания кода, и он имеет много долгосрочных преимуществ. Его будет легче читать, понимать, поддерживать, проверять, он будет менее подвержен неожиданным ошибкам и, как правило, значительно упростит жизнь другим разработчикам, когда им придется взаимодействовать с таким кодом.

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

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

Чтобы помочь вам в этом, эта статья будет охватывать несколько вопросов, которые вы должны учитывать при написании более читаемого кода и его влияния на читаемость, в том числе:

Длина кода

Насколько тесно связанный код сгруппирован вместе

Сложные конструкции JavaScript

Сколько потоков обрабатывается одновременно

Именование переменных

Выделение сходства и различия

Надеюсь, эта информация предоставит вам прочную основу для написания более читаемого кода React прямо сейчас и в будущем.

Длина кода

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

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

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

Возьмем концепцию встроенного условного рендеринга, когда он находится между оператором AND и тернарным оператором.

const Component = ({ linkUrl }) => ( <div> { !!linkUrl && <PrettyLink url={linkUrl} /> } </div>
} // -- OR -- const Component = ({ linkUrl }) => { return ( <div> {linkUrl !== undefined && linkUrl !== null ? ( <PrettyLink url={linkUrl} /> ) : null} </div> );
};

Первое является более коротким и лаконичным, а второе — длинным и уместным только тогда, когда необходимы обе ветви условия.

Но использование оператора && означает, что одна ветвь не указана явно, поэтому читатель должен выяснить, каково ожидаемое поведение для другой ветки (даже если она ничего не отображает), было ли оно пропущено по ошибке и искать информацию, которая ему не предоставляется.

Это явная жертва явности ради экономии на длине кода. Будет ли это более читаемым, зависит от сценария, но не всегда бывает так просто, как «чем короче, тем лучше».

Насколько тесно связанный код сгруппирован вместе

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

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

К сожалению, если методы жизненного цикла были разбросаны по компоненту и в некоторых случаях были написаны в определенном порядке — ваша логика была разбита и распределена по компоненту. Это увеличивало расстояние между связанными блоками кода и часто затрудняло просмотр и понимание логического потока.

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

Сложные конструкции JavaScript

В конце концов, большая часть разработки React — это JavaScript. Реализация компонентов, логики, хуков и прочего в React выполняется на JavaScript, а это значит, что для всего этого можно использовать JavaScript. Это может быть как преимуществом, так и недостатком.

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

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

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

Отсутствие этой информации может существенно отрицательно повлиять на удобочитаемость. Хотя вполне вероятно, что большинство разработчиков React знают о них, это не является гарантией и, следовательно, о таких конструкциях нужно помнить.

Функция Array.reduce для преобразования данных

const idObjects = ids.reduce((prev, curr) => { return { ...prev, [curr]: { id: curr, value: getValueFromId(id), } };
}, {});

Функция Array.reduce часто используется для преобразования массива в другую структуру данных, например в объект. Код очень компактен, но часто бывает трудным для понимания — нужно отслеживать множество деталей:

Исходный массив

Вызов reduce

Предыдущее значение

Текущее значение

Исходная структура

Полученная структура

Как сочетаются разные значения

Порядок этой информации также неестественный, как и исходная структура, определяемая последней. Еще одна улучшенная структура — цикл for. Хотя он считается более громоздким и многословным, результирующий код часто более читабелен из-за более простого порядка информации:

Сначала идет инициализация переменных

Потом, длина и пределы цикла.

И наконец, все действия с соответствующими переменными.

Оператор && для условного рендеринга

const Component = ({ hasImage }) => { // ... return ( <div> {hasImage && <Image />} </div> );
}

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

Однако эта конструкция работает только из-за неявного поведения JavaScript, называемого коротким замыканием. Когда выражение && вычисляется и оператор в левой части дает false, этот операнд возвращается, а определение правого операнда полностью пропускается.

Сколько потоков обрабатывается одновременно

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

React предоставляет нам множество инструментов для реализации потоков данных и логики. Вспомните о готовых хуках, таких как useState, useReducer, useEffect и useLayoutEffect, а также о возможности повторного использования логики в форме пользовательских хуков. Хотя эти инструменты позволяют разработчикам React очень легко и эффективно обрабатывать потоки, они также имеют свои недостатки в определенных сценариях.

Очень легко спутать множество потоков в одном месте. Например, несколько потоков проходят через один компонент или объединяют части логики из нескольких потоков в один хук useEffect.

const Component = ({ data }) => { // Logic... // Here, we're combining flows for the data request, empty state, filled logic state, and // server error feedback into a single `useEffect`. It feels natural, but is it readable? useEffect(() => { if (!data) { setRequestState("LOADING"); } else if (data.length === 0) { setRequestState("DONE"); triggerEmptyState(); } else { setRequestState("DONE"); if (dataIsValid(data)) { updateOtherLogicWithData(data); } else { informServerDataIsInvalid(); } } }, [data, updateOtherLogicWithData, informServerDataIsInvalid, triggerEmptyState]); // Render...
}

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

Именование переменных

Вообще, одна из самых сложных вещей в разработке программного обеспечения — это именование сущностей. Имена могут повлиять на читаемость кода или нарушить ее. Разработка на React не исключение. Но из-за составной природы React есть много сущностей, которые нужно называть. Хуки, компоненты, функции, переменные, обратные вызовы, контексты — и этот список можно продолжить.

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

Правильное присвоение имен может значительно продвинуть вас в написании более читаемого кода. Это не только улучшает читаемость кода, но также может улучшить качество кода и повысить удобство обслуживания в будущем. Вот несколько примеров:

Включите префикс в свойства компонента, чтобы указать тип API — это дает понять пользователям, какое поведение от него ожидается и как его использовать. например, вместо того, чтобы называть логическое свойство valid, рассмотрите возможность присвоения ему имени isValid; вместо validate рассмотрите возможность использования onValidate.

Если у вас есть несколько props, которые конфигурируют один и тот же аспект, вы, скорее всего, можете упростить дизайн API. Это можно быстро заметить по именам, например, наличие обоих логических prop и isLoading и isError. Использование перечисления, называемого так, чтобы захватить оба предыдущих свойства, может сделать дизайн API более понятным и менее загроможденным.

Учитывайте объем, в котором могут использоваться компоненты — если у вас есть компонент рендеринга аватара, который является общим для всей платформы, то его можно назвать Avatar, но если он специально предназначен для использования в разделе карты, тогда выгодно назвать его CardAvatar.

Назовите обратные вызовы его по результату действия, а не так, как они будут использоваться: если вам нужно предоставить обратный вызов для onChange prop компонента, то присвоение этому обратному вызову имени onChange не добавит никакой полезной информации для читателя. например, вместо этого подумайте о том, чтобы назвать его по результату действия: updateStateValue, это увеличит читаемость, потому что разъясняет, что делает обратный вызов и что произойдет, когда соответствующее событие произойдет в используемом компоненте.

Это конкретные примеры того, как именование переменных может изменить читаемость и качество кода React. Но именование сущностей не ограничивается приведенными примерами — самое важное — помнить об этой теме при написании, учитывать качество и специфику своего стиля именования и, возможно, улучшить его.

Выявление сходств или различий в коде React

При разработке React существует множество различных типов кода — CSS, JS, HTML (или JSX) — и из-за этого большая часть кода находится в одном месте. Это означает, что особенно в такой области разработки, ориентированной на пользовательский интерфейс, будет много сценариев, в которых код будет иметь либо незначительные сходства, либо различия. Правильное выделение таких случаев может существенно повлиять на читаемость кода. Учтите следующее:

const SomeSection = ({ isEditable, value }) => { if (isEditable) { return ( <OuterSection> <Header>Edit this content</Header> <Body>{value}</Body> <SectionButton>Clear content</SectionButton> </OuterSection> ); } return ( <OuterSection> <Header>Read this content</Header> <Body>{value}</Body> </OuterSection> );
} // -- OR -- const SomeSection = ({ isEditable, value }) => { return ( <OuterSection> <Header> { isEditable ? "Edit this content" : "Read this content"} </Header> <Body>{value}</Body> { isEditable ? <SectionButton>Clear content</SectionButton> : null } </OuterSection> );
}

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

Заключение

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

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

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

Автор: Chak Shun Yu

Источник: blog.logrocket.com

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен