Хабрахабр

[Из песочницы] Лучшие практики React и советы, которые каждый разработчик должен знать. Часть 1

Привет, Хабр! Представляю вашему вниманию перевод статьи «React Best Practices & Tips Every React Developer Should Know Pt.1» автора Alex Devero.

image

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

Содержание:

  1. Сохраняйте ваши компоненты небольшими
  2. Избегайте нагромождения компонентов
  3. Сократите использование stateful-компонентов
  4. Используйте функциональные компоненты с хуками и memo вместо компонентов на классах
  5. Не используйте props в исходном state.

Эпилог: Лучшие практики React и советы, которые каждый разработчик должен знать Часть 1

1. Сохраняйте ваши компоненты небольшими

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

Взгляните на метод render. Есть одно проверенное практическое правило, которое вы можете использовать. Помните, что одной из идей использования React, или частью его философии, является возможность повторного использования кода. Если в нем более 10 строк, то ваш компонент, вероятно, слишком велик, и является хорошим кандидатом для рефакторинга и разделения на несколько меньших компонентов.

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

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

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

Было

///
// file: index.jsx
import React from 'react'
const books = [ , { category: 'Philosophy', price: '$25.00', name: 'The Daily Stoic', author: 'Ryan Holiday' }, { category: 'Sport', price: '$15.95', name: 'Moneyball', author: 'Michael Lewis' }, { category: 'Biography', price: '$21.00', name: 'Titan', author: 'Ron Chernow' }, { category: 'Business', price: '$29.99', name: 'The Hard Thing About Hard Things', author: 'Ben Horowitz' }, { category: 'Fiction', price: '$4.81', name: 'Limitless: A Novel', author: 'Alan Glynn' }
]
class Bookshelf extends React.Component { render() { const tableRows = [] this.props.books.forEach((book) => { tableRows.push( <tr> <td>{book.name}</td> <td>{book.author}</td> <td>{book.price}</td> <td>{book.category}</td> </tr> ) }) return ( <div> <form> <input type="text" placeholder="Search..." /> <button>Search</button> </form> <table> <thead> <tr> <th>Name</th> <th>Author</th> <th>Price</th> <th>Category</th> </tr> </thead> <tbody>{tableRows}</tbody> </table> </div> ) }
}
// Render Bookshelf component
ReactDOM.render(<Bookshelf books={booksData} />, document.getElementById('container'))

Стало

///
// file: books-data.js
const books = [ { category: 'Business', price: '$20.00', name: 'Private Empires', author: 'Steve Coll' }, { category: 'Philosophy', price: '$25.00', name: 'The Daily Stoic', author: 'Ryan Holiday' }, { category: 'Sport', price: '$15.95', name: 'Moneyball', author: 'Michael Lewis' }, { category: 'Biography', price: '$21.00', name: 'Titan', author: 'Ron Chernow' }, { category: 'Business', price: '$29.99', name: 'The Hard Thing About Hard Things', author: 'Ben Horowitz' }, { category: 'Fiction', price: '$4.81', name: 'Limitless: A Novel', author: 'Alan Glynn' }
]
export default booksData
///
// file: components/books-table.jsx
import React from 'react'
class BooksTable extends React.Component { render() { const tableRows = [] this.props.books.forEach((book) => { tableRows.push( <tr> <td>{book.name}</td> <td>{book.author}</td> <td>{book.price}</td> <td>{book.category}</td> </tr> ) }) return ( <table> <thead> <tr> <th>Name</th> <th>Author</th> <th>Price</th> <th>Category</th> </tr> </thead> <tbody>{tableRows}</tbody> </table> ) }
}
export default BooksTable
///
// file: components/search-bar.jsx
import React from 'react'
class SearchBar extends React.Component { render() { return ( <form> <input type="text" placeholder="Search..." /> <button>Search</button> </form> ) }
}
export default SearchBar
///
// file: components/bookshelf.jsx
import React from 'react'
// Import components
import BooksTable from './components/books-table'
import SearchBar from './components/search-bar'
class Bookshelf extends React.Component { render() { return ( <div> <SearchBar /> <BooksTable books={this.props.books} /> </div> ) }
}
export default Bookshelf
///
// file: index.jsx
import React from 'react'
// Import components
import Bookshelf from './components/bookshelf
// Import data
import booksData from './books-data'
// Render Bookshelf component
ReactDOM.render(<Bookshelf books={booksData} />, document.getElementById('container'))

2. Избегайте нагромождения компонентов

Каждое правило должно применяться с осторожностью. Это также относится и к этим лучшим практикам React, особенно предыдущей. Когда дело доходит до компонентов, очень легко переусердствовать и написать даже мельчайшие фрагменты кода в виде компонентов. Не делай этого. Нет смысла делать так, чтобы каждый параграф, span или div был компонентом.
Думайте, прежде чем начать делить каждый компонент на мелкие части. Вы можете думать о компоненте как о смеси из «HTML», которая делает только одно, будучи независима, и пользователь воспримет ее как единое целое. Имеет ли смысл сделать этот кусок кода компонентом? Если нет, объедините этот код. Иначе, разделите его.

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

Да, некоторые из этих элементов могут существовать независимо друг от друга. На практике это бессмысленно. Что будет дальше? Однако действительно ли полезно создавать компонент, состоящий только из одного абзаца или одного заголовка? Такой подход не является устойчивым. Компонент для label, input или даже span?

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

Примерами молекул могут быть модальный диалог, форма, всплывающее окно, выпадающее меню, навигация и т.д. Затем вы объединяете атомы и создаете молекулы. Примером организма может быть заголовок, список товаров или корзина для покупок. Далее, вы можете комбинировать одну молекулу с другой или с атомом и создавать организм. Шаблоны, страницы и утилиты теперь не важны.

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

В конце концов, именно вы будете работать с кодом. В подобных случаях я предлагаю не задумываться над лучшими практиками React'а, и просто руководствоваться своим внутренним чутьем. Так что не надо просто слепо следовать какому-то списку передовых практик. Важно то, что вам удобно. Поделитесь своими мыслями об этом со своими коллегами. А если ты работаешь в команде?

3. Сократить использование stateful-компонентов

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

После того, как они были официально представлены, разработчики React больше не ограничивались stateful-компонентами, так как им нужно было использовать состояние. Хуки изменили это. Благодаря хукам разработчики React теперь могут писать функциональные компоненты (stateless), используя при этом state и даже методы жизненного цикла по своему желанию.

Компоненты без состояния или функциональные компоненты, как правило, лучше, чем stateful-компоненты, когда речь заходит о производительности. Почему это важно? Другими словами, меньше кода для выполнения, а также для транспайлинга. Причина в том, что нет ни состояния, ни методов жизненного цикла. Конечно, эта разница может быть едва ощутимой, почти невидимой, если вы работаете над каким-то очень маленьким проектом.

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


// Button defined as a stateful component
class Button extends React.Component { handleClick = () => { // Do something } render() { return( <button type="button" onClick={this.handleClick}>Click me</button> ) }
}
// Button defined as a functional component
const Button = () => { const handleClick = () => { // Do something } return( <button type="button" onClick={handleClick}>Click me</button> )
}

4. Используйте функциональные компоненты с хуками и memo вместо компонентов на классах

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

Многие разработчики React выступали против функциональных компонентов. И еще кое-что. Когда что-то меняется, React возвращает функциональный компонент, независимо от того, был ли сам компонент изменен.
В прошлом решение заключалось в использовании чистого компонента. Одна из проблем заключается в том, что вы, как разработчик React, не можете контролировать процесс рендеринга при использовании функционального компонента. Значит, React может «проверять», изменилось ли содержание компонента, props или самого компонента. Чистый компонент обеспечивает возможность сравнения состояния и props. В противном случае он пропустит повторный рендеринг и будет повторно использовать последний отрисованный результат. Если да, то он вернёт его. 6. Меньше рендеринга равнозначно лучшей производительности.
С выпуском React 16. Что изменило игру, так это memo. 0 это больше не проблема, и аргумент против функциональных компонентов больше недействителен. Memo принесла неглубокое сравнение с функциональным компонентом, возможность «проверить», изменилось ли содержание компонента, props или самого компонента.

Короче говоря, memo позволяет создавать «чистые» функциональные компоненты. Опять же, основываясь на этом сравнении, React либо вернет компонент назад, либо повторно использует результат последнего рендеринга. По крайней мере, если вам не нужно справляться со сложным состоянием. Больше нет причин использовать statefull-компоненты, или чистые компоненты.

Другим возможным вариантом могло бы стать использование контекста. В этом случае вам следует рассмотреть возможность использования чего-то более масштабируемого и управляемого, например, MobX, Redux или Flux, вместо состояния компонентов. В любом случае, благодаря хукам и memo, функциональные компоненты, безусловно, являются одними из лучших практик React, о которых стоит задуматься.

5. Не используйте props в исходном state

Это одна из лучших практик React, о которой я хотел бы знать, когда начинал изучение. Тогда я не знал, что это была очень плохая идея — использовать props в исходном состоянии. Почему это плохая идея? Проблема в том, что конструктор вызывается только один раз, во время создания компонента.

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

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

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

Эпилог: React Лучшие практики и советы, которые каждый разработчик должен знать Часть 1

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

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

Если вам понравилась эта статья, тогда, пожалуйста, подпишитесь.

Первоначально опубликовано в блоге Alex Devero Blog.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть