8

Vì vậy, vài tuần trước, trong khi thảo luận với nhóm của tôi về cách tiếp cận phát triển các thành phần React độc lập, tôi đã tình cờ thấy công cụ tuyệt vời này: Storybook . Thật ngạc nhiên, tôi đã thấy điều này trước đây, trong ví dụ về ngày phản ứng.

Storybook về cơ bản là một sân chơi để phát triển các thành phần của bạn và hành vi của chúng. Nó cũng phục vụ như tài liệu cho thư viện thành phần của bạn. Bạn có thể giới thiệu các thành phần của mình và các thay đổi khác nhau của chúng được liên kết với đạo cụ. Sau khi chơi một chút với Storybook và xem bài nói chuyện này trên Storybook Driven Development, tôi quyết định làm một hướng dẫn thực tế về cách giúp bạn bắt đầu.

Vì vậy, như bạn đã biết, React là một thư viện để tạo Giao diện người dùng. Trong những năm qua, do các thư viện như các thành phần được tạo kiểu , mối quan tâm trong việc tạo các thành phần độc lập (kiểu dáng và JSX trong một tệp JavaScript) đã tăng lên trong cộng đồng React. React Native bắt đầu phong trào này và tôi luôn là một fan hâm mộ của nó. Về vấn đề này, Storybook giúp chúng tôi thiết kế đóng gói và phát triển các thành phần của chúng tôi.

Vậy tôi cần gì để bắt đầu?

Vì vậy, chúng tôi sẽ bắt đầu với một bảng sạch:

npx create-react-app storybook-driven-development
npm i -g @storybook/cli

Điều hướng đến dự án của bạn và thêm các phụ thuộc sau:

npm install --save styled-components

Sau đó, để thêm Storybook vào dự án của bạn, bạn chỉ cần chạy:

getstorybook

Điều này sẽ tự động thêm Storybook vào dự án của bạn và thêm các phụ thuộc cần thiết. Để chạy phiên bản Storybook của dự án của bạn, chỉ cần chạy:

npm run storybook

Bây giờ bạn có thể điều hướng đến http: // localhost: 9009 / và xem sân chơi của bạn với Storybook. Dễ không

Viết câu chuyện đầu tiên của bạn

Vì vậy, toàn bộ quan điểm của Storybook Driven Development là bạn thực sự phác họa bản thân các thành phần của bạn trước tiên bằng mã trước khi thực sự mã hóa việc thực hiện. Đây có thể là một khởi đầu tuyệt vời cho sự phát triển của các thành phần của bạn bởi vì bạn có thể nghĩ về các trạng thái khác nhau mà bạn muốn thành phần của mình có trước khi bạn thực hiện. Ví dụ: nếu bạn muốn tạo thành phần Nút, bạn có thể tạo thành phần cảnh báo mặc định, chính, thông tin, nguy hiểm và cảnh báo (Hello Bootstrap!). Nhưng trông nó thế nào?

Trước hết, bạn sẽ thấy một thư mục truyện có tệp index.js. Ở đây bạn sẽ tìm thấy một số mã ví dụ về cách viết truyện. Đối với các ví dụ về nút của chúng tôi, chúng tôi có thể bắt đầu với điều này:

import React from 'react';
import { storiesOf } from '@storybook/react';
import {Button, H1} from  '../components/shared';
import { action } from '@storybook/addon-actions';
import { withInfo } from '@storybook/addon-info';
import { text, boolean, number } from '@storybook/addon-knobs/react';


const stories = storiesOf('Button', module);


stories
  .add('Primary', () => <Button type="primary" size="lg">Primary button</Button>)
  .add('Default', () =><Button type="default" size="lg" >Default</Button>)
  .add('Info', () => <Button type="info" size="lg">Info button</Button>)
  .add('Warning', () => <Button type="warning" size="sm">Warning</Button>)
  .add('Danger', () => <Button type="danger" size="xs">!</Button>)
  .add('Testing default props', () => <Button>Default props</Button>)

Khá đơn giản phải không? Nếu chúng tôi để Storybook biên dịch cái này, nó sẽ báo lỗi vì bạn không có thành phần Nút. Vì vậy, hãy làm cho một.

import React from 'react';

export default (props) => {
  return(
    <button>
      {props.text}
    </button>
  )
}

Sau khi phiên bản đầu tiên của thành phần nút được tạo, chúng ta đã có thể thấy các nút của mình trong sách truyện.

Sau này, chúng ta có thể bắt đầu thực sự mã hóa trạng thái trong các thành phần của mình và kiểm tra chúng trong sách truyện. Đối với điều này, chúng tôi sẽ sử dụng các thành phần theo kiểu. Chúng ta có thể bắt đầu bằng cách thêm các nhập thành phần theo kiểu và làm cho trình bao bọc nút của chúng ta. Sau đó, chúng ta có thể bắt đầu chơi với các đạo cụ được đưa ra để tạo ra các trạng thái khác nhau. Button  Thành phần của chúng tôi  sẽ trông như thế này:
import React from 'react'
import styled from "styled-components";
import PropTypes from 'prop-types';


const ButtonWrapper = styled.button`
  background-color: ${props => {
    switch (props.type) {
      case 'primary':
        return 'green';
      case 'default':
        return 'blue';
      case 'info':
        return 'yellow';
      case 'warning':
        return 'orange';
      case 'danger':
        return 'red';
      default:
        return 'blue';
    }
  }};
  font-weight:600;
  font-size:${(props) => props.theme.fontSize};
  padding:0.5em;
  color:white;
  border-radius:0.5em;
  width:${props => {
    switch (props.size) {
      case 'xs':
        return '4em';
      case 'sm':
        return '8em';
      case 'md':
        return '12em';
      case 'lg':
        return '16em';
      default:
        return '8em';
    }
  }}
`;

const Button = (props) => (<ButtonWrapper {...props}>{props.children} </ButtonWrapper>)

Button.defaultProps = {
  type: 'primary'
}

Button.propTypes = {
  //** Indicates which kind of button it is. */
  type: PropTypes.string,
}

export default Button;

Việc thực hiện theo kế hoạch chi tiết cuốn sách của tôi , có nghĩa là tôi sẽ viết thành phần của mình theo câu chuyện của tôi. Trong những câu chuyện của chúng tôi, chúng tôi có hai đạo cụ: loạikích thước . Chúng tôi cũng có con của thành phần mà trong trường hợp này sẽ hiển thị văn bản nút của chúng tôi. Trên đầu trang của chúng tôi là phong cách của chúng tôi. Sử dụng các thành phần theo kiểu có điều kiện đặt một số kiểu cụ thể. Đối với màu nền và chiều rộng của nút, chúng tôi đã sử dụng loại và kích thước. Chúng tôi cũng có thể xác định đạo cụ mặc định của mình trong trường hợp bạn quên đặt đạo cụ. Điều này có thể được thực hiện với các loại prop như thế này:

const Button = (props) => (<ButtonWrapper {...props}>{props.children} </ButtonWrapper>)

Button.defaultProps = {
  type: 'primary'
}

Button.propTypes = {
  //** Indicates which kind of button it is. */
  type: PropTypes.string,
}

export default Button;

Sau khi thực hiện, các nút của chúng tôi sẽ có một số cuộc sống.

Addon

Vì vậy, điều thú vị về Storybook là số lượng tiện ích bổ sung sẽ giúp cho sự phát triển của bạn dễ dàng hơn và dễ dự đoán hơn. Tôi sẽ nhấn mạnh một vài trong số này. Để bắt đầu với các tiện ích bổ sung này, bạn phải chạy:

npm i --save-dev @storybook/addon-actions @storybook/addon-info @storybook/addon-viewport storybook-addon-styled-component-theme @storybook/addon-knobs

Sau này, chúng ta phải thực hiện một số điều chỉnh trong các tệp addons.js và config.js ( cd ./storybook )

addons.js:

import '@storybook/addon-actions/register';
import '@storybook/addon-viewport/register';
import '@storybook/addon-knobs/register'
import 'storybook-addon-styled-component-theme/dist/register';

config.js

import { configure, addDecorator } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs/react';

addDecorator(withKnobs);

function loadStories() {
  require('../src/stories');
}
configure(loadStories, module);

Hành động

Sử dụng các hành động trong Storybook khá đơn giản. Bạn chỉ cần nhập chức năng hành động và sử dụng nó trong trình xử lý của bạn:

stories
  .add('Primary', () => <Button type="primary" onClick={action('Clicked!')} size="lg">Primary button</Button>)

Sau đó, khi nhấp vào nút của bạn, bạn sẽ nhận được một mục trong logger hành động của bạn.

vớiInfo

Các withInfo addon cung cấp cho bạn thông tin thêm về thành phần của bạn. Bạn có thể đặt một mô tả cho thành phần của bạn và xem JSX ban đầu cũng như các đạo cụ mà thành phần hỗ trợ.

stories
  .add('Default', withInfo('This is an informational paragraph you can use to describe your component')(
    () =><Button type="default" size="lg" onClick={action('onClick')}>Default</Button>
  ))

Và đây là giao diện của nó trong Storybook:

Núm

Các Knobs addon cho phép bạn thay đổi đạo cụ tự động từ UI truyện. Ví dụ, chúng tôi muốn thêm một chức năng bị vô hiệu hóa vào nút của chúng tôi và chúng tôi cũng muốn thay đổi màu sắc nếu nó bị vô hiệu hóa. Trong những câu chuyện sẽ như thế này:

stories.add('Warning', () => 
  <Button disabled={boolean('Disabled', false)} type="warning" size="sm">Warning</Button>)

Bạn sử dụng các chức năng tiện ích từ tiện ích bổ sung các nút để nó biết loại núm nào sẽ hiển thị. Trong trường hợp này, đó là một boolean và nó sẽ hiển thị một hộp kiểm. Sau đó chúng ta cần thêm thay đổi cho màu bị tắt:

background-color: ${props => {
    if(props.disabled){
      return 'grey';
    }
    switch (props.type) {
      case 'primary':
        return 'green';
      case 'default':
        return 'blue';
      case 'info':
        return 'yellow';
      case 'warning':
        return 'orange';
      case 'danger':
        return 'red';
      default:
        return 'blue';
    }
  }};

Và trong hành động:

Khung nhìn

Viewport cũng là một addon rất hữu ích vì bạn có thể kiểm tra khả năng phản hồi của các thành phần. Nó cung cấp mô phỏng chế độ xem thiết bị giống như trong Chrome.

Phần thưởng: Chủ đề Với các thành phần được tạo kiểu

Một tính năng lớn mà các thành phần theo kiểu cung cấp là ThemeProvider. ThemeProvider là một thành phần trình bao bọc cho ứng dụng của bạn sẽ hỗ trợ chủ đề cho các thành phần của bạn. Điều này sẽ cho phép bạn thay đổi kiểu dáng của bạn dựa trên chủ đề bạn đã xác định. Trong sách truyện, bạn có thể thay đổi chủ đề từ UI.

Vì vậy, hãy thay đổi mã của chúng tôi để nó hỗ trợ Theming. Chúng tôi có thể xác định chủ đề của mình trong một tệp JavaScript riêng:

export const coolblue = {
  name: "Coolblue theme",
  fontSize: '0.9rem',
  h1Size: '2.8rem',
  h1Color:'#285dab'
};


export const airbnb = {
  name: "Airbnb theme",
  fontSize: '0.9rem',
  h1Size: '2.8rem',
  h1Color:'#FF5A5F'
};

export const amazon = {
  name: "Amazon theme",
  fontSize: '0.9rem',
  h1Size: '2.8rem',
  h1Color:'black'
}

Sau đó, chúng tôi có thể bọc App.js của mình với ThemeProvider và điều chỉnh cấu hình sách truyện của mình để nó hỗ trợ các chủ đề.

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { amazon, coolblue, airbnb } from '../src/components/themes/themes';
import Button from './components/shared/Button';
import { ThemeProvider } from "styled-components";

class App extends Component {
  render() {
    return (
      <ThemeProvider theme={airbnb}>
        <div className="App">
          <Button type="default" size="lg">Default</Button>
        </div>
      </ThemeProvider>
    );
  }
}

export default App;

config.js:

import { configure, addDecorator } from '@storybook/react';
import {amazon, airbnb, coolblue} from '../src/components/themes/themes';
import { withKnobs } from '@storybook/addon-knobs/react';
import {withThemesProvider} from 'storybook-addon-styled-component-theme';

const themes = [amazon, airbnb, coolblue];
addDecorator(withThemesProvider(themes));
addDecorator(withKnobs);

function loadStories() {
  require('../src/stories');
}
configure(loadStories, module);

Sau này, chúng ta có thể tạo một câu chuyện tiêu đề và nó được thực hiện để hiển thị chức năng của chủ đề.

câu chuyện:

const h1Stories = storiesOf('h1', module);
h1Stories
  .add('H1 element', () => <H1>This is a very simple Heading component</H1>)

thực hiện:

import React from 'react'
import styled from "styled-components";
import PropTypes from 'prop-types';


const H1wrapper = styled.h1`
  color:${(props) => props.theme.h1Color};
  font-size:${(props) => props.theme.h1Size};
`;

const H1 = (props) => (<H1wrapper {...props}>{props.children} </H1wrapper>)

export default H1;

Và xem nó trong hành động:

Phần kết luận

Có rất nhiều lợi ích khi dùng thử Storybook và SDD. Nó sẽ hợp lý hóa quá trình thiết kế và tạo thành phần của bạn, nó sẽ đóng vai trò là tài liệu để đưa lên các nhà phát triển mới trong nhóm của bạn và cũng giúp bạn áp dụng thiết kế thành phần được đóng gói. Phần thưởng thêm vào của việc kiểm tra các thành phần của bạn cũng rất hay và có nhiều tiện ích cộng đồng sẽ giúp trải nghiệm truyện của bạn hiệu quả hơn. Nó cũng có thể được sử dụng với Angular và Vue.

Cảm ơn bạn đã đọc! Nếu bạn thích những bài viết như thế này hãy cho tôi biết trong phần bình luận!

PS: Tất cả các mã cho bài viết này có thể được tìm thấy trên repo này .

|