Статьи

React Storybook: разрабатывайте красивые пользовательские интерфейсы с легкостью

Реактивный сборник рассказов

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

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

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

Зачем вам нужен сборник рассказов?

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

Дизайнер или эксперт по UX

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

разработчик

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

тестер

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

Владелец продукта

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

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

Если мне удалось убедить вас, давайте посмотрим, как мы можем настроить Storybook в проекте.

Настройка React Storybook

Чтобы настроить React Storybook, в первую очередь вам понадобится проект React. Если у вас нет подходящего на данный момент, вы можете легко создать его с помощью create-реагировать-приложение .

Чтобы создать сборник рассказов, установите getstorybook глобально

 npm i -g getstorybook 

Затем перейдите к вашему проекту и запустите

 getstorybook 

Эта команда сделает три вещи:

  • Установите @ kadira / storybook в свой проект.
  • Добавьте build-storybook сценариев и build-storybook в свой файл package.json .
  • Создайте папку .storybook которая содержит базовую конфигурацию и папку stories с образцом компонента и историей.

Чтобы запустить Storybook, выполните npm run storybook и откройте отображаемый адрес ( http: // localhost: 9009 / ). Приложение должно выглядеть так:

Пользовательский интерфейс React Storybook по умолчанию

Добавление нового контента

Теперь, когда у нас запущен React Storybook, давайте посмотрим, как мы можем добавлять новый контент. Каждая новая страница добавляется путем создания историй. Это фрагменты кода, которые визуализируют ваш компонент. Пример истории, созданной getstorybook выглядит следующим образом

 //src/stories/index.js import React from 'react'; import { storiesOf, action, linkTo } from '@kadira/storybook'; import Button from './Button'; import Welcome from './Welcome'; storiesOf('Welcome', module) .add('to Storybook', () => ( <Welcome showApp={linkTo('Button')}/> )); storiesOf('Button', module) .add('with text', () => ( <Button onClick={action('clicked')}>Hello Button</Button> )) .add('with some emoji', () => ( <Button onClick={action('clicked')}> </Button> )); 

Функция storiesOf создает новый раздел в меню навигации, а метод add создает новый подраздел. Вы можете структурировать сборник рассказов, как считаете нужным, но вы не можете создавать иерархии глубже двух уровней. Простым подходом к структурированию сборника рассказов является создание общих разделов верхнего уровня, таких как «Входы форм», «Навигация» или «Виджеты» для групп связанных элементов и подразделов для отдельных компонентов.

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

Истории загружаются в файл .storybook/config.js который содержит следующий код:

 import { configure } from '@kadira/storybook'; function loadStories() { require('../src/stories'); } configure(loadStories, module); 

По умолчанию он загружает файл src/stories/index.js и ожидает, что вы импортируете туда свои истории. Это немного неудобно, так как нам потребуется импортировать каждую новую историю, которую мы создаем. Мы можем изменить этот скрипт, чтобы автоматически загружать все истории, используя метод require.context в Webpack. Чтобы отличить файлы истории от остальной части кода, мы можем согласиться добавить к .stories.js расширение .stories.js . Модифицированный скрипт должен выглядеть так:

 import { configure, addDecorator } from '@kadira/storybook'; import React from 'react'; configure( () => { const req = require.context('../src', true, /.stories.js$/); req.keys().forEach((filename) => req(filename)); }, module ); configure(loadStories, module); 

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

Написание новой истории

Теперь, когда мы немного адаптировали сборник рассказов к нашим потребностям, давайте напишем нашу первую историю. Но прежде всего нам нужно создать компонент для демонстрации. Давайте создадим простой компонент Name для отображения имени в цветном блоке. Компонент будет иметь следующие JavaScript и CSS.

 import React from 'react'; import './Name.css'; const Name = (props) => ( <div className={'name ' + (props.type ? props.type : '')}>{props.name}</div> ) Name.propTypes = { type: React.PropTypes.oneOf(['highlight', 'disabled']), } export default Name; 
 .name { display: inline-block; font-size: 1.4em; background: #4169e1; color: #fff; border-radius: 4px; padding: 4px 10px; } .highlight { background: #dc143c; } .disabled { background: #999; } 

Как вы, наверное, заметили, этот простой компонент может иметь три состояния: по умолчанию, выделен и отключен. Разве не было бы неплохо представить их всех? Давайте напишем историю для этого. Создайте новый файл Name.stories.js вместе с вашим компонентом и добавьте следующее содержимое:

 import React from 'react'; import { storiesOf, action, linkTo } from '@kadira/storybook'; import Name from './Name'; storiesOf('Components', module) .add('Name', () => ( <div> <h2>Normal</h2> <Name name="Louie Anderson" /> <h2>Highlighted</h2> <Name name="Louie Anderson" type="highlight" /> <h2>Disabled</h2> <Name name="Louie Anderson" type="disabled" /> </div> )) 

Откройте сборник рассказов и взгляните на свой новый компонент. Результат должен выглядеть так:

Название истории

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

Посмотреть настройки

Если вы хотите изменить способ отображения своих историй, вы можете поместить их в контейнер. Это можно сделать с addDecorator функции addDecorator . Например, вы можете добавить заголовок «Примеры» для всех ваших страниц, добавив следующий код в .storybook/config.js :

 import { configure, addDecorator } from '@kadira/storybook'; import React from 'react'; addDecorator((story) => ( <div> <h1>Examples</h1> {story()} </div> )); 

Вы также можете настроить отдельные разделы, вызвав addDecorator после storiesOf :

 storiesOf('Components', module) .addDecorator(...) 

Публикация вашего сборника рассказов

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

 npm run build-storybook 

По умолчанию Storybook встроен в storybook-static папку storybook. Вы можете изменить каталог вывода с помощью параметра -o . Теперь вам просто нужно загрузить его на свою любимую платформу хостинга.

Если вы работаете над проектом на GitHub, вы можете опубликовать свою Storybook, просто встраивая ее в папку docs и помещая в репозиторий. GitHub может быть настроен для обслуживания вашего сайта GitHub Pages оттуда. Если вы не хотите хранить свою собранную Storybook в хранилище, вы также можете использовать storybook-deployer .

Конфигурация сборки

Сборник рассказов настроен на поддержку ряда функций внутри историй. Вы можете написать в том же синтаксисе ES2015 +, что и в create-реагировать-приложение , однако, если ваш проект использует другую конфигурацию Babel, он автоматически подберет ваш файл .babelrc . Вы также можете импортировать файлы JSON и изображения.

Если вам кажется, что этого недостаточно, вы можете добавить дополнительную конфигурацию веб-пакета, создав файл .storybook папке .storybook . Параметры конфигурации, экспортируемые этим файлом, будут объединены с конфигурацией по умолчанию. Например, чтобы добавить поддержку SCSS в ваши истории, просто добавьте следующий код:

 module.exports = { module: { loaders: [ { test: /.scss$/, loaders: ["style", "css", "sass"] } ] } } 

Не забудьте установить sass-loader и node-sass .

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

Если вы хотите добавить другую конфигурацию для сред разработки и производства, вы можете вместо этого экспортировать функцию. Он будет вызываться с базовой конфигурацией и переменной configType установлено значение «DEVELOPMENT» или «PRODUCTION».

 module.exports = function(storybookBaseConfig, configType) { // add your configuration here // Return the altered config return storybookBaseConfig; }; 

Расширение функциональности с помощью дополнений

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

Сборник рассказов поставляется с двумя предварительно настроенными надстройками: Действия и Ссылки. Вам не нужно предпринимать никаких дополнительных настроек для их использования.

действия

Действия позволяют вам регистрировать события, запускаемые вашими компонентами, на панели «Журнал действий». Взгляните на историю Button созданную Storybook. Он связывает событие onClick с помощником action , который отображает событие в пользовательском интерфейсе.

Примечание: вам может потребоваться переименовать файл, содержащий историю Button и / или изменить его местоположение на основе изменений, внесенных в .storybook/config.js .

 storiesOf('Button', module) .add('with text', () => ( <Button onClick={action('clicked', 'test')}>Hello Button</Button> )) 

Попробуйте нажать на кнопку и запишите результат в «Action logger».

Выход журнала действий

Аддон Links позволяет добавить навигацию между компонентами. Он предоставляет помощника linkTo который может быть связан с любым событием onClick :

 import { storiesOf, linkTo } from '@kadira/storybook'; storiesOf('Button', module) .add('with link', () => ( <Button onClick={linkTo('Components', 'Name')}>Go to Name</Button> )); 

Нажав на эту кнопку, вы попадете в раздел «Компонент» и подраздел «Имя».

Knobs

Дополнение Knobs позволяет настраивать ваши компоненты, изменяя свойства React во время выполнения, прямо из пользовательского интерфейса.

Для установки аддона выполните:

 npm i --save-dev @kadira/storybook-addon-knobs 

Прежде чем вы сможете использовать это дополнение, оно должно быть зарегистрировано в Storybook. Для этого создайте файл .storybook папке .storybook со следующим содержимым:

 import '@kadira/storybook/addons'; import '@kadira/storybook-addon-knobs/register'; 

После этого оберните свои истории декоратором withKnobs . Вы можете сделать это глобально в .storybook/config.js :

 import { withKnobs } from '@kadira/storybook-addon-knobs'; addDecorator(withKnobs); 

Как только мы закончим с этим, мы можем попытаться изменить историю компонента Name . Теперь вместо трех вариантов состояния компонента мы можем выбирать их в пользовательском интерфейсе. Мы также сделаем имя редактируемым. Измените содержимое Name.stories.js на:

 import React from 'react'; import { storiesOf, action, linkTo } from '@kadira/storybook'; import { text, select } from '@kadira/storybook-addon-knobs'; import Name from './Name'; const types = { '': '', highlight: 'highlight', disabled: 'disabled' } storiesOf('Components', module) .add('Name', () => ( <div> <h2>Normal</h2> <Name name={text('Name', 'Louie Anderson')} type={select('Type', types)} /> </div> )) 

Аддон предоставляет различные вспомогательные функции для создания пользовательских вводов разных типов, таких как числа, диапазоны или массивы. Здесь мы будем использовать текст для имени и выбрать тип. Откройте страницу «Имя», и новая вкладка «Ручки» должна появиться рядом с «Журнал действий». Попробуйте изменить входные значения и посмотрите, как компонент перерисовывается.

Интерфейс ручек

Информация

Информационный аддон позволяет вам добавить больше информации о статье, например, ее исходный код, описание и React propTypes. Доступность этой информации очень удобна для разработчиков.

Установите это дополнение, запустив:

 npm i --save-dev @kadira/react-storybook-addon-info 

Затем зарегистрируйте дополнение в Storybook в .storybook/config.js :

 import { setAddon } from '@kadira/storybook'; import infoAddon from '@kadira/react-storybook-addon-info'; setAddon(infoAddon); 

Это добавит дополнительный метод storiesOf объекту storiesOf для регистрации ваших историй. Он имеет немного другой API и принимает заголовок истории, описание, функцию рендеринга и дополнительную конфигурацию в качестве параметров. Используя этот метод, мы можем переписать нашу историю Name следующим образом:

 import React from 'react'; import { storiesOf, action } from '@kadira/storybook'; import Name from './Name'; storiesOf('Components', module) .addWithInfo( 'Name with info', ` A component to display a colored name tag. `, () => ( <Name name="Louie Anderson" /> ), { inline: true }, ) 

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

Пример информации

Автоматизированное тестирование

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

Характеристики

Дополнение « Спецификации» позволяет писать модульные тесты непосредственно в файлах истории. Тесты будут выполняться каждый раз, когда вы открываете Storybook, и результат отображается в пользовательском интерфейсе. После некоторой обработки вы можете также запустить эти тесты в среде CI, используя Jest.

Вам также может понравиться: Как тестировать компоненты React с помощью Jest

Storyshots

Storyshots позволяет выполнять Jest Snapshot Тесты на основе историй. Тесты моментальных снимков позволяют проверить, соответствует ли DOM, представленный компонентами, ожидаемому результату. Очень удобно для проверки правильности отображения ваших компонентов. По крайней мере, с точки зрения DOM.

Сборник рассказов как услуга

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

Вывод

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

Вы уже используете Storybook? Вы собираетесь попробовать? Почему? Или действительно, почему нет? Я хотел бы услышать от вас в комментариях.

Эта статья была рецензирована Тимом Севериеном и Джулио Майнарди . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!