Развитие шаблонов в React

razvitie shablonov v react

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

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

Сообществу понадобилось около 2 лет, чтобы согласовать несколько идей. Мы перешли из React.createClass к ES6 class и чисто функциональные компоненты Мы отказались от миксинов и упростили наши API.

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

Чтобы понять эти закономерности, вам необходимо базовое понимание Реагировать понятие и их экосистема. Однако заметьте, что я не буду рассматривать их в этой статье.

Итак начнем!

Условный рендер

Я видел следующий сценарий во многих проектах.

Когда люди думают Реагировать и JSXони все еще думают категориями HTML и JavaScript.

Поэтому естественным шагом является по отдельности условная логика по фактическому коду возврата.

const condition = true;

const App = () => {
  const innerContent = condition ? (
    <div>
      <h2>Show me</h2>
      <p>Description</p>
    </div>
  ) : null;
  
  return (
    <div>
      <h1>This is always visible</h1>
      { innerContent }
    </div>
  );
};

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

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

const condition = true;

const App = () => (
  <div>
    <h1>This is always visible</h1>
    {
      condition && (
        <div>
          <h2>Show me</h2>
          <p>Description</p>
        </div>
      )
    }
  </div>
);

Если condition есть false, второй операнд в && оператор не оценивается. Если это истина, второй операнд. или JSX, который мы хотим отразить – возвращается.

Это позволяет нам смешивать Логика пользовательского интерфейса с фактическими элементами пользовательского интерфейса в a декларативный путь!

Относитесь к JSX как к неотъемлемой части вашего кода! В конце концов, это просто JavaScript.

Передача реквизита

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

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

Хорошим способом обойти это использование деструктуризация реквизита вместе с JSX распространениекак вы можете видеть здесь:

const Details = ( { name, language } ) => (
  <div>
    <p>{ name } works with { language }</p>
  </div>
);

const Layout = ( { title, ...props } ) => (
  <div>
    <h1>{ title }</h1>
    <Details { ...props } />
  </div>
);

const App = () => (
  <Layout 
    title="I'm here to stay"
    language="JavaScript"
    name="Alex"
  />
);

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

Деструктуризационный реквизит

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

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

const Details = ( { name, language } ) => (
  <div>
    <p>{ name } works with { language }</p>
  </div>
);

class Details extends React.Component {
  render() {
    const { name, language } = this.props;
    return (
      <div>
        <p>{ name } works with { language }</p>
      </div>
    )
  }
}

Обратите внимание на то, что линии 2–4 и 11–13 есть одинаковые. Трансформировать компоненты с помощью этого шаблона гораздо проще. Кроме того, вы ограничиваете использование this внутри компонента.

Шаблон поставщика

Мы рассмотрели пример, когда реквизиты следует послать через другой компонент. Но что если вам придется отправить 15 компонентов?

Введите контекст React!

Это не обязательно наиболее рекомендуемая функция React, но она выполняет работу, когда это необходимо.

Недавно было объявлено, что Context получает новый API, реализующий шаблон провайдера из коробки.

Если вы используете такие вещи как React Redux или Apollo, вы можете быть знакомы с шаблоном.

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

Компонент верхнего уровня — называется Провайдер — устанавливает некоторые значения контекста. Вызываются дочерние компоненты Потребители – возьмет эти значения из контекста.

Текущий синтаксис контекста немного странный, но будущая версия реализует именно этот шаблон.

Компоненты высокого уровня

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

Компоненты высокого порядка – теперь HOC – вышли, чтобы удовлетворить потребность в повторном использовании поведения в нескольких компонентах.

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

Если вы используете Redux, вы поймете, что connect функция является HOC — берет ваш компонент и добавляет кучу реквизит к нему.

Давайте реализуем базовый HOC, который может добавлять свойства к существующим компонентам.

const withProps = ( newProps ) => ( WrappedComponent ) => {
  const ModifiedComponent = ( ownProps ) => ( // the modified version of the component
    <WrappedComponent { ...ownProps } { ...newProps } /> // original props + new props
  );

  return ModifiedComponent;
};

const Details = ( { name, title, language } ) => (
  <div>
    <h1>{ title }</h1>
    <p>{ name } works with { language }</p>
  </div>
);

const newProps = { name: "Alex" }; // this is added by the hoc
const ModifiedDetails = withProps( newProps )( Details ); // hoc is curried for readability

const App = () => (
  <ModifiedDetails 
    title="I'm here to stay"
    language="JavaScript"
  />
);

Если вы любите функциональное программирование, то вам понравится работать с компонентами высокого порядка. Recompose – это отличный пакет, который предоставляет вам все эти приятные утилиты, как HOC withProps, withContext, lifecycleи так дальше.

Давайте рассмотрим очень полезный пример повторное использование функций.

function withAuthentication(WrappedComponent) {
  const ModifiedComponent = (props) => {
    if (!props.isAuthenticated) {
      return <Redirect to="/login" />;
    }

    return (<WrappedComponent { ...props } />);
  };

  const mapStateToProps = (state) => ({
    isAuthenticated: state.session.isAuthenticated
  });

  return connect(mapStateToProps)(ModifiedComponent);
}

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

Это сквозной вопрос о вашей программе, реализованной в одном месте и подходящей для повторного использования по всей программе.

Однако у HOC есть и недостаток. Каждый HOC добавит дополнительный компонент React в структуру DOM/vDOM. Это может привести к потенциальным проблемам с производительностью при масштабировании программы.

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

Render Props

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

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

Некоторые люди предпочитают использовать a динамический проп для этого некоторые просто используют this.props.children.

Я знаю, это все еще очень запутано, но давайте посмотрим простой пример.

class ScrollPosition extends React.Component {
  constructor( ) {
    super( );
    this.state = { position: 0 };
    this.updatePosition = this.updatePosition.bind(this);
  }
  
  componentDidMount( ) {
    window.addEventListener( "scroll", this.updatePosition );
  }

  updatePosition( ) {
    this.setState( { position: window.pageYOffset } )
  }

  render( ) {
    return this.props.children( this.state.position )
  }
}

const App = () => (
  <div>
    <ScrollPosition>
      { ( position ) => (
        <div>
          <h1>Hello World</h1>
          <p>You are at { position }</p>
        </div>
      ) }
    </ScrollPosition>
  </div>
);

Вот мы используем children как сопротивление визуализации. Внутри <ScrollPosition> компонент мы вышлем функцию, которая получитs the poрасположение как параметр.

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

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

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

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

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

Какие узоры вы используете? Кто из них подойдет к этой статье? Напишите мне сообщение ниже или напишите мнения в Twitter.

Если вы нашли эту статью полезной, помогите мне поделиться ею с сообществом!

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

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