Узнайте, как эффективно структурировать и организовывать компоненты React.

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

1. Принцип единой ответственности

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

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

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

Вот пример того, как мы можем применить SRP в составе компонентов React:

// UserCard component responsible for displaying user information
const UserCard = ({ user }) => {
  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
      {/* Additional user information */}
    </div>
  );
};

// EditUserButton component responsible for editing a user
const EditUserButton = ({ onClick }) => {
  return <button onClick={onClick}>Edit User</button>;
};

// DeleteUserButton component responsible for deleting a user
const DeleteUserButton = ({ onClick }) => {
  return <button onClick={onClick}>Delete User</button>;
};

Разделив обязанности на разные компоненты, мы можем легко повторно использовать компонент «UserCard» в различных контекстах, сохраняя при этом чистую и сфокусированную кодовую базу.

2. Компонентная композиция на основе реквизита

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

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

Давайте посмотрим на пример, где мы создаем компонент «Кнопка» с разными реквизитами:

const Button = ({ text, onClick }) => {
  return <button onClick={onClick}>{text}</button>;
};

// Composing the Button component with different props
const App = () => {
  return (
    <div>
      <Button text="Click me" onClick={() => console.log("Button clicked")} />
      <Button text="Submit" onClick={() => console.log("Submit clicked")} />
      <Button text="Cancel" onClick={() => console.log("Cancel clicked")} />
    </div>
  );
};

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

3. Составные компоненты

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

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

Чтобы реализовать составные компоненты, мы можем использовать контекст React для обмена состоянием или другими необходимыми данными между компонентами. Это позволяет компонентам координировать свои действия и без проблем работать вместе.

Давайте рассмотрим пример компонента Tabs, где у нас есть компонент TabsList для отображения списка вкладок и компонент TabPanel для отображения содержимого выбранной вкладки:

const TabsContext = React.createContext();

const Tabs = ({ children }) => {
  const [activeTab, setActiveTab] = React.useState(0);
  const handleTabClick = (index) => {
    setActiveTab(index);
  };
  return (
    <TabsContext.Provider value={{ activeTab, onTabClick: handleTabClick }}>
      {children}
    </TabsContext.Provider>
  );
};

const TabsList = ({ children }) => {
  const { activeTab, onTabClick } = React.useContext(TabsContext);
  return (
    <div>
      {React.Children.map(children, (child, index) =>
        React.cloneElement(child, {
          isActive: index === activeTab,
          onClick: () => onTabClick(index),
        }),
      )}
    </div>
  );
};

const Tab = ({ children, isActive, onClick }) => {
  return (
    <button
      onClick={onClick}
      style={{ fontWeight: isActive ? 'bold' : 'normal' }}
    >
      {children}
    </button>
  );
};

const TabPanel = ({ children }) => {
  const { activeTab } = React.useContext(TabsContext);
  return <div>{children[activeTab]}</div>;
};

const App = () => {
  return (
    <Tabs>
      <TabsList>
        <Tab>Tab 1</Tab>
        <Tab>Tab 2</Tab>
        <Tab>Tab 3</Tab>
      </TabsList>
      <TabPanel>
        <div>Content for Tab 1</div>
        <div>Content for Tab 2</div>
        <div>Content for Tab 3</div>
      </TabPanel>
    </Tabs>
  );
};

export default App;

В этом примере компонент Tabs предоставляет состояние activeTab и функцию onTabClick через TabsContext.Provider. Компонент TabsList и компонент Tab используют состояние activeTab и функцию onTabClick из контекста для обработки выбора и рендеринга вкладок.

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

4. Рендер реквизит

Render Props — это еще один метод композиции компонентов в React. Он включает в себя передачу функции в качестве реквизита компоненту, что позволяет компоненту отображать свой вывод с использованием предоставленной функции.

Используя шаблон Render Props, компоненты могут предоставлять гибкий и компонуемый API, который позволяет потребителям управлять поведением рендеринга. Это обеспечивает мощные возможности настройки и расширения.

Давайте рассмотрим пример, в котором у нас есть компонент Toggle, который предоставляет состояние переключения и функцию переключения своим дочерним элементам, используя шаблон Render Props:

const Toggle = ({ children }) => {
  const [on, setOn] = React.useState(false);

  const toggle = () => {
    setOn((prevOn) => !prevOn);
  };
  return children({ on, toggle });
};
const App = () => {
  return (
    <Toggle>
      {({ on, toggle }) => (
        <div>
          <button onClick={toggle}>{on ? 'ON' : 'OFF'}</button>
          {on && <p>The toggle is ON</p>}
        </div>
      )}
    </Toggle>
  );
};

В этом примере компонент Toggle показывает свое состояние (включено) и поведение (переключение) через дочернюю функцию. Потребители могут предоставить свою собственную логику рендеринга, используя предоставленное состояние и функцию.

Шаблон Render Props обеспечивает динамическую и гибкую композицию, поскольку потребители имеют полный контроль над визуализацией вывода компонента.

5. Компоненты высшего порядка (HOC)

Компоненты высшего порядка (HOC) — это шаблон в React, где функция берет компонент и возвращает новый компонент с расширенными функциями.

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

Чтобы создать HOC, мы определяем функцию, которая принимает компонент в качестве аргумента и возвращает новый компонент с дополнительными функциями. HOC может модифицировать props, обернуть компонент дополнительными элементами или предоставить данные через контекст.

Давайте посмотрим на пример HOC, который добавляет индикатор загрузки к компоненту:

const withLoadingIndicator = (Component) => {
  return function WithLoadingIndicator({ isLoading, ...props }) {
    if (isLoading) {
      return <div>Loading...</div>;
    }
    return <Component {...props} />;
  };
};

const MyComponent = ({ data }) => {
  return <div>{data}</div>;
};
const MyComponentWithLoadingIndicator = withLoadingIndicator(MyComponent);
const App = () => {
  const isLoading = true;
  const data = 'Hello, world!';
  return (
    <div>
      <MyComponentWithLoadingIndicator isLoading={isLoading} data={data} />
    </div>
  );
};

В этом примере withLoadingIndicator HOC принимает компонент и возвращает новый компонент (WithLoadingIndicator), который отображает индикатор загрузки, если свойство isLoading истинно. В противном случае он отображает исходный компонент.

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

Заключение

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

  1. Принцип единой ответственности: разрабатывайте компоненты с единой ответственностью, чтобы улучшить возможность повторного использования и удобство сопровождения.
  2. Состав компонентов на основе реквизита: создавайте компоненты, передавая различные реквизиты для достижения различной функциональности или внешнего вида.
  3. Составные компоненты: разрабатывайте компоненты, которые работают вместе и взаимодействуют через общее состояние или контекст, чтобы обеспечить более высокий уровень абстракции и гибкости.
  4. Render Props: используйте шаблон Render Props, чтобы предоставить функцию в качестве реквизита, позволяя потребителям управлять поведением рендеринга компонента.
  5. Компоненты высшего порядка (HOC): создавайте HOC для обертывания компонентов и добавления дополнительных возможностей или сквозных задач без изменения их исходной реализации.

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

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

Дополнительные материалы на PlainEnglish.io.

Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .