предисловие
Недавно я обнаружил, что есть еще технический пост в блоге, который я не написал в этом месяце~, хотя я могу просто взять статью, накопленную за день, или вынуть некоторые моменты недавнего рефакторинга, я могу обмануть прошлое, но я решил что то сделать.. . .
Недавно появилось такое требование. В проекте рефакторинга, над которым я работаю, есть некоторые компоненты, которые я хочу извлечь и использовать для других проектов в будущем. Затем мне нужно разработать два фронтенд-проекта. общие компоненты. Чисто статические страницы не подходят, потому что у меня сейчас React + Typescipt в моем стеке технологий. Я хочу быть подключи и играй. Кстати, определите props, state и другие вещи, и вы сможете изменить проект позже. Изначально я ставил флаг, чтобы приготовить что-то самому, но в группе WeChat кто-то скинул ссылкуstorybook,
На первый взгляд кажется, что это то, что мне нужно. Итак, сегодняшняя цель — поиграться со средой разработки.
Определите потребности
Storybook — это среда разработки компонентов пользовательского интерфейса. Он позволяет просматривать библиотеку компонентов, просматривать различные состояния каждого компонента, а также интерактивно разрабатывать и тестировать компоненты.
Но введение официального гитхаба очень плохое, так что предлагаю вам его посмотретьIntroduction to StorybookУзнать больше.
так же какguide
Уточним наши потребности:
- Поддержка загрузки библиотек пользовательского интерфейса, таких как ant-design
- Поддержка машинописного текста
- поддержка редукса
- Поддержка отладки параметров
Официально начать
По идее, сначала создайте реактивный проект, поддерживающий ts
create-react-app my-app --scripts-version=react-scripts-ts
Затем обновите зависимости
yarn upgrade
затем следуйте сборник рассказов
npm i -g @storybook/cli
cd my-app
getstorybook
бежать сразу заyarn run storybook
вы можете увидеть интерфейс
Однако правда не так проста. Потому что ts поддерживается самим проектом, а сборник рассказов независим. Поэтому вам нужно сделать различные модификации в соответствии с конфигурацией.
первый в.storybook
Создано в каталогеwebpack.config.js
загрузить внутрьtypescript-loader
// load the default config generator.
const genDefaultConfig = require('@storybook/react/dist/server/config/defaults/webpack.config.js');
module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
// Extend it as you need.
// For example, add typescript loader:
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('awesome-typescript-loader')
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
тогда правильноpackage.json
сделать макияж
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-scripts-ts": "2.7.0"
},
"scripts": {
"start": "react-scripts-ts start",
"build": "react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"devDependencies": {
"@storybook/addon-actions": "^3.2.12",
"@storybook/addon-links": "^3.2.12",
"@storybook/react": "^3.2.12",
"@types/jest": "^21.1.2",
"@types/node": "^8.0.39",
"@types/react": "^16.0.12",
"@types/react-dom": "^16.0.1",
"@types/storybook__react": "^3.0.5",
"awesome-typescript-loader": "^3.2.3"
}
}
Самый важный момент после этого — поместить корневую директориюstories
каталог перемещен вsrc
под каталогом.
Напишиindex.tsx
import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';
import { Button, Welcome } from '@storybook/react/demo';
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>);
бежать заyarn run storybook
Вы можете добиться поддержки синтаксиса ts.
После этого нам нужно подумать о том, как должны быть организованы наши компоненты пользовательского интерфейса.Глядя на исходный код на gitHub, есть два основных способа.
Один из них — добавить его непосредственно под одноименным компонентом..stories.ts
документ
./Button.jsx
./Button.stories.ts
одинstories
Создайте index.ts в каталоге, чтобы ссылаться на другие компоненты.
Берем последнюю, что для удобства управления. И это можно сделать прямо на основе нашего существующего кода.
Мы рассматриваем возможность сделать демо, сейчасreact
+ redux
Все демо используютсяtodolist
Что нужно сделать. Но тут мы прямо подставляем зрелогоredux
строить планы.
Сначала мы видимsrc
Текущая структура каталога:
.
├── App.css
├── App.test.tsx
├── App.tsx
├── index.css
├── index.tsx
├── logo.svg
├── registerServiceWorker.ts
├── stories
│ └── index.jsx
├── webpack.config.1.js
└── webpack.config.js
явно типичныйcreate-app
Структура.
Затем мы смотрим непосредственно на структуру проекта после добавления редукса:
── src
│ ├── actions
│ │ └── index.ts
│ ├── components
│ ├── constants
│ │ └── index.ts
│ ├── containers
│ │ └── App
│ ├── index.tsx
│ ├── logo.svg
│ ├── reducers
│ │ ├── index.ts
│ │ └── info.ts
│ ├── registerServiceWorker.ts
│ ├── store
│ │ └── index.ts
│ ├── stories
│ │ └── index.jsx
│ ├── typing.d.ts
│ ├── webpack.config.1.js
│ └── webpack.config.js
Здесь также важно отметить, что вам необходимоtsconfig
Чтобы сделать что-то целое и поддержать Less, я также внес некоторые изменения в webpack.
Затем пишем простуюaction to reducer
action:
import { INFO_LIST } from '../constants/index'
const saveList = (data: Object) => ({
type: INFO_LIST,
data: data,
})
export function infoListRemote () {
const info = {
data: {
item: 'Hello LinShuiZhaoYing',
cnItem: '你好, 临水照影'
}
}
return (dispatch: any) => {
dispatch(saveList(info))
return info
}
}
reducer:
import { INFO_LIST } from '../constants';
const initialState = {
info:''
}
const info = (state = initialState, action: any) => {
// console.log(action)
switch (action.type) {
case INFO_LIST:
return {
...state,
info:action.data.data
}
default:
return state
}
}
export default info;
App:
index.tsx:
import * as React from 'react';
import { Button, Icon } from 'antd';
import { connect } from 'react-redux';
import { infoListRemote } from '../../actions/index';
import './index.css';
class App extends React.Component<any, any> {
constructor (props: any) {
super(props)
this.state = {
infoList: '',
}
}
componentWillMount() {
}
componentDidMount() {
// console.log(this.props)
}
componentWillReceiveProps(nextProps: any) {
// console.log(nextProps)
if (nextProps.info) {
this.setState({
infoList: nextProps.info.item
})
}
}
getInfo = () => {
const { dispatch } = this.props;
dispatch(infoListRemote())
}
render() {
return (
<div className="App">
<div className="test"> {this.state.infoList} </div>
<Button type="danger" onClick={this.getInfo}> Click Me</Button>
<Icon type="play-circle-o" />
</div>
);
}
}
const mapStateToProps = (state: any) => ({
info: state.info.info,
})
let AppWrapper = App
AppWrapper = connect(mapStateToProps)(App);
export default AppWrapper;
Тогда посмотрите на рендеры:
Вы можете видеть, что данные были успешно доставлены.
Далее нужно написатьstories
, потому что мы использовалиredux
Поэтому нам нужно использоватьaddDecorator
чтобы обернуть наши компоненты
import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';
import { Provider } from 'react-redux';
import { Button, Welcome } from '@storybook/react/demo';
import { createBrowserHistory } from 'history';
import configureStore from '../store';
import AppWrapper from '../containers/App'
const store = configureStore(createBrowserHistory);
storiesOf('AppWrapper', module)
.addDecorator(story => <Provider store={store}>{story()}</Provider>)
.add('empty App', () => <AppWrapper />);
storiesOf('Button', module)
.add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
.add('with some emoji', () => <Button onClick={action('clicked')}>😀 😎 👍 💯</Button>);
Последний шаг — добавить отладку параметров, здесь нам нужно добавить некоторыеaddon
для повышения опыта.
мы можемMore addonsСписок дополнений смотрите здесь. Увеличение в соответствии со спросом. Затем перейдите на соответствующий веб-сайт git, чтобы увидеть использование и присоединиться.
присоединиться первымaddon-notes
, он используется для написания описания компонента, и после тестирования его можно добавить в Html-код, чтобы вы могли сначала определить единый формат самостоятельно, а затем добавлять контент.
Вы также можете настроить некоторую информацию, такую как использование параметров, открытые интерфейсы и т. д. нагрузкаInfo Addon
может быть достигнут.
Следующим ядром является увеличение функции отладки параметров
Вот пример фрагмента кода:
storiesOf('AppWrapper', module)
.addDecorator(withKnobs)
.addDecorator(story => <Provider store={store}>{story()}</Provider>)
.add('knobs App', () =><AppWrapper text={text('Label', 'Hello World')}></AppWrapper>)
.add('with all knobs', () => {
const name = text('Name', 'Tom Cary');
const dob = date('DOB', new Date('January 20 1887'));
const bold = boolean('Bold', false);
const selectedColor = color('Color', 'black');
const favoriteNumber = number('Favorite Number', 42);
const comfortTemp = number('Comfort Temp', 72, { range: true, min: 60, max: 90, step: 1 });
const passions = array('Passions', ['Fishing', 'Skiing']);
const customStyle = object('Style', {
fontFamily: 'Arial',
padding: 20,
});
const style = {
...customStyle,
fontWeight: bold ? 800 : 400,
favoriteNumber,
color: selectedColor,
};
return (
<div style={style}>
I like: <ul>{passions.map((p, i) => <li key={i}>{p}</li>)}</ul>
<p>My favorite number is {favoriteNumber}.</p>
<p>My most comfortable room temperature is {comfortTemp} degrees Fahrenheit.</p>
</div>
);
});
Вам необходимо установить динамически передаваемые параметры во время разработки. Это может быть отображено немедленно. Схема эффекта выглядит следующим образом:
тогда позвониaddon options
Добавьте в config.js
setOptions({
downPanelInRight: true,
})
Измените доску отображения горизонтальной оси на вертикальную.
Есть еще много интересногоaddons
, такие как улучшенная версия Inforeadme
.и смена фона в один кликbackgrounds
. Существуют также существующиеMaterial-UI
. Существует также прямое отображение вашего исходного кода Jsx.Storybook-addon-jsx
.и контрольная версия показываетstorybook-addon-versions
, что позволяет напрямую сравнивать различия между несколькими версиями. Генерация всех скриншотов в один кликStorybook Chrome Screenshot Addon
. эти сообществаaddons
очень полезны. Если вы заинтересованы, вы можете добавить его самостоятельно.
конец
Наконец, мы отлично выполнили предыдущие требования, и есть несколько неожиданных сюрпризов.
Согласно моей конфигурации среды, он может быть расширен сам по себе, хотя я сейчас разрабатываю на основе React. ноStoryBook
Также поддерживает Vue.
Наконец-то выложили проект как обычногитхаб-адрес
использованная литература
Схема разработки фронтенд-компонента и его применение в React Native