TL; DR вы можете (и должны) создавать компоненты React, которые ничего не отображают, и использовать их для управления данными и состоянием в вашем приложении, чтобы иметь компоненты, которые можно повторно использовать и компоновать по-настоящему.

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

Если я прошу людей получить некоторые данные из имитационного API и отобразить список, большинство из них заканчивают писать что-то вроде этого:

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

Рефакторинг: состав, SRP и SOC

Компоненты должны быть составными (кажется очевидным, не так ли? 😉) и должны иметь только одну единственную ответственность (SRP), чтобы помочь достичь разделения ответственности (SOC). В нашем примере есть несколько обязанностей / проблем: получение данных и отображение различных состояний пользовательского интерфейса. Наш компонент нужно разбить на части:

  • У нас будет компонент без рендеринга Fetch, который можно использовать для извлечения данных из любой конечной точки REST (с помощью GET). Он будет использовать рендеринг, чтобы передать своим потомкам состояние, связанное с получением данных.
  • В качестве плюса у нас будут три чистых функциональных компонента для отображения различных состояний пользовательского интерфейса: Loading, Error и данные List. List сможет отображать данные любого типа, используя другую опору рендеринга: renderItem
  • Наш компонент DataList свяжет все эти части вместе.
  • Наши крошечные части могут быть повторно использованы в других частях нашего приложения и содержат по одной проблеме каждая.

Сплоченность без сцепления: такая победа! 😊

Альтернатива: используйте HOC

Вы можете использовать HOC вместо рендеринга для достижения тех же результатов, но лично я предпочитаю рендеринг-реквизиты: он позволяет нам контролировать, как реквизиты передаются в компоненты пользовательского интерфейса. В любом случае, если вы хотите, довольно легко получить HOC, если у вас есть API на основе рендеринга:

Мы просто делаем то, что уже делают все остальные

Мы здесь не заходим за рамки. Мы только что сделали то, что уже делают многие разработчики, чтобы создать действительно многоразовые и гибкие компоненты. Если вы использовали какую-нибудь библиотеку для выборки данных, такую ​​как react-apollo, то шаблон, который мы видели, должен быть вам знаком. Взгляните на пример response-apolloQuery ниже. Знакомо?

Если вы прочитаете документацию response-apollo, вы сможете получить представление о том, как обрабатывать такие вещи, как опрос или изменение данных в API, и реализовывать их в нашем Fetch компоненте.

Этот шаблон широко известен как Компоненты контейнера (спасибо Сирегар за указание на это). Дэн Абрамов тоже придерживался этого подхода, но теперь перешел на использование крючков. Кстати о крючках…

Введите крючки

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

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

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

Подводя итоги

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

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

Наконец, помните, что управление данными - это широкое понятие, не ограничивающееся использованием REST или GraphQL API. Все, что не является пользовательским интерфейсом, - это данные. Подумайте о библиотеках, таких как Redux, которые обрабатывают глобальное состояние, или react-fns, которые предоставляют доступ к нескольким веб-API с использованием компонентов React. Все они построены на этих концепциях.