Привет, Хабр! Представляю вашему вниманию перевод статьи «Learn Render Props by Example».
Честно говоря, раньше я не представлял ситуаций, в которых можно применить React render props, пока не увидел практический пример, поэтому, поехали! Или можете прочитать TLDR;
Ситуация:
Нам поручено создать кнопку, открывающую окно PayPal:
Мы открываем наш редактор и создаем компонент PayPalLauncher:
PayPalLauncher может содержать экземпляр PayPal, с дополнительной логикой, поэтому неплохо было бы обернуть его (PayPal) в компонент.
Но что, если требуется использовать дополнительные элементы PayPal? Например:
Теперь у нас есть две кнопки и оранжевая ссылка, которая должна открыть окно PayPal. Давайте рассмотрим несколько способов реализовать это.
Вариант 1 – Логика в render()
Вначале у вас может возникнуть соблазн написать код внутри PayPalLauncher:
Здесь мы передаем prop, называемый type для того, чтобы определить какой элемент PayPal рендерить. Много логики, чтобы выразить несколько визуальных изменений. Это все еще не дает нам возможности легко отрисовывать любой компонент по необходимости. Что если есть способ отделить логику от представления?
Вариант 2 — Вложенность
Вложенность помогает нам писать более понятный JSX.
Теперь у нас есть четкое разделение между логикой (PayPalLauncher) и представлением (PayPalButton). Это дает нам возможность отображать любой компонент в качестве элемента PayPal (PayPal trigger). И это хорошо читается! Но как мы передаем props между PayPalLauncher и PayPalButton? Давайте посмотрим как это выглядит в PayPalLauncher:
Что здесь происходит?! Мы клонируем children и предаем prop в launchPayPal неявно, каждому ребенку. Это значит, что каждый ребенок, которого вы вложите в PayPalLauncher, должен принимать prop launchPayPal. Хотя вложенность дает нам более понятный JSX, этот метод не является идеальным, особенно если мы пытаемся создать переиспользуемые компоненты с общими интерфейсами.
Вариант 3 — Render Props
Render Props — это метод передачи props от родителя ребенку, используя функцию или замыкание. Давайте посмотрим, как это выглядит:
Вместо того, чтобы обрабатывать props.children в качестве ноды, мы создаем замыкание и выбираем аргументы для передачи дочерним нодам. В этом случае мы используем метод экземпляра класса launchPayPal.
Когда мы реализуем это, полученный вариант будет выглядеть так:
Что это значит? Вместо элементов, мы передаем функцию как ребенка в PayPalLauncher. Из-за этого мы можем легко передать launchPayPal в обработчик onClick компонента PayPalButton. Теперь мы можем рендерить любой нужный нам компонент, и мапить родительский launchPayPal в любой обработчик ребенка.
Немного больше:
Неожиданным преимуществом использования render props является то, что этот подход дает возможность передавать launchPayPal в Page, и позволяет нам добавлять больше функциональности. Например, допустим, вы хотите зарегистрировать пользователя и подтвердить форму перед запуском окна PayPal:
Поскольку launchPayPal отображается через render props на Page, мы можем легко добавить дополнительный контекстно-зависимый функционал, используя композицию функций. Здесь мы сохраняем разницу между Page и PayPalLauncher и используем pipe, чтобы улучшить читаемость.
Резюме
Что мы получаем при использовании render props?
Вы тоже беспокоитесь о работе ваших React приложений? Открыты вакансии!
* Помните, что render props является паттерном и может быть реализован несколькими способами — только вы должны выбирать, что использовать с вашем случае.
Честно говоря, раньше я не представлял ситуаций, в которых можно применить React render props, пока не увидел практический пример, поэтому, поехали! Или можете прочитать TLDR;
Ситуация:
Нам поручено создать кнопку, открывающую окно PayPal:
Мы открываем наш редактор и создаем компонент PayPalLauncher:
PayPalLauncher может содержать экземпляр PayPal, с дополнительной логикой, поэтому неплохо было бы обернуть его (PayPal) в компонент.
Но что, если требуется использовать дополнительные элементы PayPal? Например:
Теперь у нас есть две кнопки и оранжевая ссылка, которая должна открыть окно PayPal. Давайте рассмотрим несколько способов реализовать это.
Вариант 1 – Логика в render()
Вначале у вас может возникнуть соблазн написать код внутри PayPalLauncher:
Здесь мы передаем prop, называемый type для того, чтобы определить какой элемент PayPal рендерить. Много логики, чтобы выразить несколько визуальных изменений. Это все еще не дает нам возможности легко отрисовывать любой компонент по необходимости. Что если есть способ отделить логику от представления?
Вариант 2 — Вложенность
Вложенность помогает нам писать более понятный JSX.
Теперь у нас есть четкое разделение между логикой (PayPalLauncher) и представлением (PayPalButton). Это дает нам возможность отображать любой компонент в качестве элемента PayPal (PayPal trigger). И это хорошо читается! Но как мы передаем props между PayPalLauncher и PayPalButton? Давайте посмотрим как это выглядит в PayPalLauncher:
Что здесь происходит?! Мы клонируем children и предаем prop в launchPayPal неявно, каждому ребенку. Это значит, что каждый ребенок, которого вы вложите в PayPalLauncher, должен принимать prop launchPayPal. Хотя вложенность дает нам более понятный JSX, этот метод не является идеальным, особенно если мы пытаемся создать переиспользуемые компоненты с общими интерфейсами.
Вариант 3 — Render Props
Render Props — это метод передачи props от родителя ребенку, используя функцию или замыкание. Давайте посмотрим, как это выглядит:
Вместо того, чтобы обрабатывать props.children в качестве ноды, мы создаем замыкание и выбираем аргументы для передачи дочерним нодам. В этом случае мы используем метод экземпляра класса launchPayPal.
Когда мы реализуем это, полученный вариант будет выглядеть так:
Что это значит? Вместо элементов, мы передаем функцию как ребенка в PayPalLauncher. Из-за этого мы можем легко передать launchPayPal в обработчик onClick компонента PayPalButton. Теперь мы можем рендерить любой нужный нам компонент, и мапить родительский launchPayPal в любой обработчик ребенка.
Немного больше:
Неожиданным преимуществом использования render props является то, что этот подход дает возможность передавать launchPayPal в Page, и позволяет нам добавлять больше функциональности. Например, допустим, вы хотите зарегистрировать пользователя и подтвердить форму перед запуском окна PayPal:
Поскольку launchPayPal отображается через render props на Page, мы можем легко добавить дополнительный контекстно-зависимый функционал, используя композицию функций. Здесь мы сохраняем разницу между Page и PayPalLauncher и используем pipe, чтобы улучшить читаемость.
Резюме
Что мы получаем при использовании render props?
- Переиспользование логики — отделяя отображение от логики, нам не нужно подгонять логику под каждый компонент или визуальное представление.
- Чистый и хорошо читаемый JSX.
- Улучшается структура и функциональная составляющая наших React приложений.
Вы тоже беспокоитесь о работе ваших React приложений? Открыты вакансии!
* Помните, что render props является паттерном и может быть реализован несколькими способами — только вы должны выбирать, что использовать с вашем случае.
Комментарии (3)
m_vash Автор
02.08.2018 12:48Ребят, поставьте кто-то плюс в карму плз. Сразу выставлю статью о способах стилизации реакт компонентов, а то с минусовой следующую смогу только через неделю
Cobalt
После абзаца «PayPalLauncher может содержать экземпляр PayPal, с дополнительной логикой, поэтому неплохо было бы обернуть его (PayPal) в компонент:» явно не хватает изображения
m_vash Автор
Спасибо, исправил. Там была ошибка пунктуации.