Coder Social home page Coder Social logo

benjycui.github.io's People

Contributors

benjycui avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

benjycui.github.io's Issues

听音乐,学英语

学习是一件很枯燥的事,还是一件很有趣的事?因人而异,也因方法而异。而这篇文章,将会向各位分享一下在学英语过程中可以使用的一个相对有趣的方法,听音乐。或者更准确一点,听英文歌。其实这个方法并不新鲜,想必各位都听说过。类似的学英语的方法还有看剧、看书,当然必需是英文的。

考虑到程序员的风格,在介绍任何东西的时候,都需要一个 Quick Start。所以接下来,本文会给出具体的步骤,并用实例演示,同时也会指出这个方法优于看剧、看书的点。

步骤

首先当然是得有喜欢的英文歌,实在没有,可以找人推荐下。

  1. 找到这首歌对应的歌词;
  2. 把歌词读一遍,碰到不懂的单词就查词典,推荐 Collins,想偷懒可以用有道;
  3. 分析歌词中的组合,最好还找一下相似的组合;
  4. 背歌词,背歌词,背歌词;
  5. 经常去听这首歌,并在听的时候尽量回想之前做的功课;

每次描述步骤都觉得在写菜谱,囧。

栗子

为了方便,本文就只是分析句子中的组合。以 Because you live 为例:

Staring out at the rain with a heavy heart

It's the end of the world in my mind

Then your voice calls me back like a wake up call

*I've been looking for* the answer
#1. have been doing
#    曾经做过某事,强调做这件事持续的时间,并且可能还会继续下去,如:
#      I have been programming for *five years*.
#2. have done
#    曾经做过某事,强调所做的事,如:I have *programmed* for five years.

Somewhere

I couldn't see that it was right there

But now I know what I really know

Because you live and breathe

Because you make me *believe in* myself when nobody else can help
#1. believe somebody
#    相信某人说的话,如:I believe Tom.
#2. believe in somebody
#    相信某人(人品之类),如:I believe in Tom.

Because you live, girl

My world has twice as many stars in the sky

It's alright, I survived, I'm alive again

*Cuz* of you, made it though every storm
# cuz => because,其实歌词中是有着大量口语化的单词,除了 cuz,常见的还有:
#   * wanna => want to
#   * gonna => going to

What is life, whats the use if you killed inside

I'm so glad I found an angel

Someone

Who was there when all my hopes fell

I wanna fly, looking in your eyes

# 省略若干行相似的歌词

Because you live and breathe

Because you make me believe in myself when nobody else can help

Because you live, girl

My world has everything I *need to survive*
#1. need to do something
#    需要(主动)去做某事,如:I need to wash this shirt.
#2. need to be done / need doing
#    需要被什么,如:1) This shirt needs to be washed. 2) This shirt needs washing.

Because you live, I live, I live

查自己不懂的单词相对容易,所以稍微说一下怎么分析歌词中的组合。以 I've been looking for the answer 为例:

  1. 把缩写替换掉:I have been looking for the answer
  2. 分析句子结构,得出句子是 主+谓+宾 的结构,主语、宾语相对简单,所以重点看谓语:have been looking for
  3. 简化 have been looking forhave been doing
  4. Google 之
  5. 另外在 Google 的时候,可以从搜索建议中看到 have been doing and have done,也 Google 一下

需要说明一下的是,句子结构分析属于语言学的范围,但并不需要太深入的学习语言学。因为歌词,以及技术文档中的句子基本都是简单句,所以分析起来相对容易,并不需要太多的语言学知识。

相对于看剧、看书的优点

最重要的是,时间成本低。一首歌也就几分钟的时间(串烧除外),而且大多数情况下我们都是一边听歌一边做其它的事情。

其次,对于喜欢的歌,我们都会反复去听,自然会有较深的记忆。

同时,歌词内的单词、句型相对常用。虽然没有看剧时学的台词常用,但比看书时学到的要常用得多。

再怎么不济,去 KTV 的时候装一下 X 也好。:D

最后...

其实歌词只是一个载体,帮助我们回忆起之前学过的单词、句型等。所以最终能学到多少,还是由在分析歌词的过程中查找到的信息所决定的。

另外,还记得自己刚开始学 Emacs 的时候,看过一句话。大概如下:

Don't learn Emacs, use it!

毕竟任何技巧、方法,都只是一个辅助,要掌握一个技能,必需去使用它。所以在用各种方法学英语的时候,别忘了,use it!

bisheng

问题:我想使用bisheng去搭建一个类似antd官网的说明性网站,看了bisheng简单的例子,是把markdown转化为页面,有一个问题是,我怎么去使用router,使菜单具有层级性,看例子中没有合适的说明,希望能得到解答,谢谢!

关于Ant Design中Form.List的使用

您好!
我在学习使用Ant Design进行开发,并在Ant Design的文档上看到您是文档贡献者。在使用Form组件时遇到一个问题,希望向您请教。
我使用了Form.List组件去动态增减表单项,如果我想为这些动态表单项设置初始值,应该怎样处理?我使用 form.setFieldsValue({...}) 的方法,只能实现对静态表单项的赋值,这样的动态表单项目前还没有想到比较好的解决办法。

下面是我写的表单

form

这里是动态表单项

formitem

这段是我参照文档写的代码
{
chargeOnPeriod === true && (
<Form.List name="periodPrices">
{(fields, { add, remove }) => {
console.log(Children)
return (
<>
<Form.Item label="单价">
<Button
className="addPrice"
type="link"
onClick={() => { add(); }}
>
添加时段

</Form.Item>
{fields.map((field, index) => (


<Form.Item name={[field.name, 'prices']} fieldKey={[field.fieldKey, 'prices']}>
元/度
</Form.Item>


<Form.Item name={[field.name, 'hours']} fieldKey={[field.fieldKey, 'hours']}>

</Form.Item>


{fields.length >= 1 ? (
<MinusCircleOutlined className="dynamic-delete-button"
onClick={() => { remove(field.name); }}
/>
) : null}


))}
</>
)
}}
</Form.List>
)
}

希望不吝赐教,谢谢!

the ant.design issue bot is way too aggresive and possibly buggy

Hi!

Nice project, ant.design! I believe you are the maintainer, right?

I tried filing a bug on ant.design which has bad layout on firefox android (title texts go offscreen on both sides).

Issue form is hard to fill from mobile, but worse, all my text disappeared after pressing Create leading me to an empty issue screen.

Looking at the Closed Issues I notice that other well-meaning contributors of bug reports got their issues similarly closed.

The issue bot is too aggressive, and probably has some bugs when posting.

Just saying.. but it discourages contributing :)

Great Habits of Programmer

Most of you heard about Refactoring: Improving the Design of Existing Code, which is written by Kent Beck. And some of you may know that Kent Beck said:

I'm not a great programmer; I'm just a good programmer with great habits.

But what are those great habits?

Kent Beck had provide some in his book. Also, you can find others through searching engine. Actually, maybe searching engine is the reason that you are reading this article. But for me, the following habits are what I have learned from my classmates and colleagues. It is useful for me. So, I share them to you and hope that these habits make you a better programmer.

Create indexes instead of reciting while reading books and so on

It is exciting or tiring for programmers that they have to learn thousands of new technologies in order to catch up with the development of industry (especially for front-end engineers). Programmers are cleaver enough to learn new technologies, but most of them do not have enough time, for their lives have been occupied by countless meetings and requirements. And then, this trick is to help programmers save time and learn new technology quickly.

Let's see...

Create indexes => Just remember how to find the answer for a specific question

Recite => Try to store the answer in your head

So, this trick means that remember how to find the answer for a question instead of storing the answer in your head.

Take jQuery for example. It is possible to remember all the APIs of jQuery, but difficult. Actually, it is unnecessary for most of programmers to remember all the APIs of a library. What we should do is that scan those APIs and know what they can do. In another word, we do not need to know how to do with those APIs. Because we know that we can open http://api.jquery.com/ and search, anytime.

Also, it is unnecessary to remember all the tricks in Refactoring. We read this book, and knew some tricks which make our code better. When need to know how to do that, we can just consult this book.

Reorganize what you had learned

Knowledge is not breadcrumbs that are unordered and uncorrelated. So, we need to reorganize what we had learned from books and bugs and so on.

But how to do?

It depends on you 囧. As for me, writing blogs is the answer. When writing blogs, I must review what I had learned. If something makes me puzzled, I will search on the Internet or ask others. Actually, I learn more while writing a blog.

Also, sharing what you had learned to others is another answer. Your audiences will throw questions at you. And you have to reorganize what you had learn in order to make everything clear.

Read unit test and source code

A well-designed document is the best gift for a programmer, for this document will help programmers start quickly, and provide answers for most of questions. But the real world is not utopia, some libraries' documents are in a mess. What is worse, some libraries do not have any document.

So, don't be afraid of codes that are written by others, even if there is no comment. Anyway, it is the only way to understand a library without document. And read unit test is still a good choice, for it shows what the author expects this library to do or not to do.

But...

What if...

There is no unit test!

Read source code of the library, and try to guess what it is designed to do from the implementation. Or, just find a well-documented library, if you can.

Think twice before coding

You can code at home, at table, at ... But you can not code at will. Coding is rigorous for your code will have a great effect on customers and your annual bonus.

As for me, think twice means that ask myself some questions. For example:

  1. What do I expect this program to do?
  2. How does current version work?
  3. Why do I choose this solution? Is there a better solution?

Ask yourself all the questions that you care about.

Look at $$$, think twice before coding, or thrice for important things should be repeated thrice :).

你好,我想问一下,tabs切换时form表单的数据能不能跟着刷新呢,我现在遇到的问题是切换第二页就没有数据了

image

image

这是完整代码
import { Line } from '@antv/g2plot';
import {Button, Card, DatePicker, Input, Form, Radio, Select, Tabs} from 'antd';
import {connect} from 'dva'
import React, { useState, useRef } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import styles from './style.less';

const { TabPane } = Tabs;
const FormItem = Form.Item;
const { Option } = Select;
const { RangePicker } = DatePicker;
const { TextArea } = Input;
let linePlot;

@connect(({auth_user, loading}) => ({
// auth_user,
// loading: loading.effects['auth_user/handleListData'],
// listData: auth_user.listData,
// pagination: auth_user.pagination,
// // msg: auth_user.msg,
// // searchAdvanceStatus: auth_user.searchAdvanceStatus,
// // searchStatus: auth_user.searchStatus,
// // dealStatus: auth_user.dealStatus,
// searchParams: auth_user.searchParams,
}))

export default class UpdateForm extends React.Component {

data = [
    { year: '1991', value: 3 },
    { year: '1992', value: 4 },
    { year: '1993', value: 3.5 },
    { year: '1994', value: 5 },
    { year: '1995', value: 4.9 },
    { year: '1996', value: 6 },
    { year: '1997', value: 7 },
    { year: '1998', value: 9 },
    { year: '1999', value: 13 },
];

constructor(props) {
    super(props);
    this.formRef = React.createRef();
    this.newTabIndex = 0;
    const panes = [
        { title: 'Tab 1', content: 'Content of Tab Pane 1', key: '1',  closable: false},
        { title: 'Tab 2', content: 'Content of Tab Pane 2', key: '2',  closable: false},
    ];
    this.state = {
        activeKey: panes[0].key,
        panes,
    };
}

componentDidMount(){
    this.formData();
    this.drawRangeMapCharts(this.data);
}
formData = () => {
    this.formRef.current.setFieldsValue({
        title: this.props.location.query.channelId,
        subject: 'china',
        categories: 'usa',
        publicType: '1',
        categoriesw: 'second',
        test: '2',
        categoriesw4: 'third',
    });
    console.log(this.props.location.query.channelId)
}
//绘制血缘关系图
drawRangeMapCharts(data){
    linePlot = new Line(document.getElementById('container'), {
        title: {
            visible: true,
            text: '带数据点的折线图',
        },
        description: {
            visible: true,
            text: '将折线图上的每一个数据点显示出来,作为辅助阅读。',
        },
        width: 700,
        height: 463,
        forceFit: false,
        padding: 'auto',
        data,
        xField: 'year',
        yField: 'value',
        point: {
            visible: true,
        },
        label: {
            visible: true,
            type: 'point',
        },
    });
    linePlot.render();
}
//重置表单
handleReSetForm = () => {
   this.formRef.current.resetFields();
};
onFinish = values => {
   // console.log(values);
}
handleDifficulty = () => {
        const data2 = [
          { year: '2016', value: '重要' },
          { year: '2017', value: '一般' },
          { year: '2018', value: '容易' },
          { year: '2019', value: '容易' },
          { year: '2020', value: '一般' },
        ];
        linePlot.destroy();
        this.drawRangeMapCharts(data2)
}
handleChange = () => {
    const data3 = [
      { year: '2016', value: '一星' },
      { year: '2017', value: '二星' },
      { year: '2018', value: '一星' },
      { year: '2019', value: '三星' },
      { year: '2020', value: '三星' },
    ];
    linePlot.destroy();
    this.drawRangeMapCharts(data3)
}


onChange = activeKey => {

    this.setState({ activeKey });
    this.formRef.current.setFieldsValue({
        title: '232334',
        subject: 'china',
        categories: 'usa',
        publicType: '1',
        categoriesw: 'second',
        test: '2',
        categoriesw4: 'third',
    });
};

add = () => {
    const { panes } = this.state;
    const activeKey = `newTab${this.newTabIndex++}`;
    panes.push({ title: 'New Tab', content: 'New Tab Pane', key: activeKey,  closable: false  });
    this.setState({ panes, activeKey });
};

onEdit = (targetKey, action) => {
    this[action](targetKey);
};

render(){
  const { submitting,resetting } = this.props;
  const {activeKey} = this.state;
  const formItemLayout = {
    labelCol: {
      xs: {
        span: 8,
      },
      sm: {
        span: 5,
      },
    },
    wrapperCol: {
      xs: {
        span: 24,
      },
      sm: {
        span: 12,
      },
      md: {
        span: 10,
      },
    },
  };
  const submitFormLayout = {
    wrapperCol: {
      xs: {
        span: 0,
        offset: 0,
      },
      sm: {
        span: 0,
        offset: 5,
      },
    },
  };
  console.log(this.formRef)
  //2、创建dom
    return(
        <PageHeaderWrapper>
            <div className={styles.divAll}>
                <Tabs
                    onChange={this.onChange}
                    activeKey={this.state.activeKey}
                    type="editable-card"
                    onEdit={this.onEdit}
                    className={styles.flex}
                >
                    {this.state.panes.map(pane => (
                        <TabPane tab={pane.title} key={pane.key} closable={pane.closable} className={styles.margin}>

                            {pane.content}
                            <Form
                                style={{
                                    marginTop: 8,
                                }}
                                ref={this.formRef}
                                name="basic"
                                onFinish={this.onFinish}
                                // onFinishFailed={onFinishFailed}
                            >
                                <FormItem
                                    {...formItemLayout}
                                    label='知识点名称'
                                    name="title"
                                    rules={[
                                        {
                                            required: true,
                                            message: "请输入知识点",
                                        },
                                    ]}
                                >
                                    <Input placeholder='给知识点起个名字'/>
                                </FormItem>
                            </Form>
                            {/*{ activeKey == this.state.activeKey ?     :<div> </div>}*/}
                        </TabPane>
                    ))}
                </Tabs>
                <div id='container' className={styles.lineChart} />
            </div>
        </PageHeaderWrapper>
    );
}

}

// <FormItem
// {...formItemLayout}
// label='所属考种'
// name="subject"
// hasFeedback
// rules={[
// {
// required: true,
// message: "请选择所属考种",
// },
// ]}
// >
// // China // U.S.A //
//
// <FormItem
// {...formItemLayout}
// label='所属科目'
// name="categories"
// hasFeedback
// rules={[
// {
// required: true,
// message: "请选择所属科目",
// },
// ]}
// >
// // China // U.S.A //
//
// <FormItem
// {...formItemLayout}
// label='难易程度'
// name="publicType"
// >
// <Radio.Group onChange={this.handleDifficulty} >{/onChange={this.handleDifficulty}/}
//
// 容易
//
//
// 中等
//
//
// 较难
//
// </Radio.Group>
//
// <FormItem
// {...formItemLayout}
// label='重要程度'
// name="categoriesw"
// hasFeedback
// rules={[
// {
// required: true,
// message: "请选择重要程度",
// },
// ]}
// >
// // 一星 // 二星 // 三星 //
//
// <FormItem
// {...formItemLayout}
// label='是否为考点'
// name="test"
// >
// <Radio.Group>
//
// 是
//
//
// 否
//
// </Radio.Group>
//
// <FormItem
// {...formItemLayout}
// label='年份'
// name="categoriesw4"
// hasFeedback
// rules={[
// {
// required: true,
// message: "请选择重要程度",
// },
// ]}
// >
// // 一星 // 二星 // 三星 //
//
// <FormItem
// {...submitFormLayout}
// style={{
// marginTop: 32,
// }}
// >
//
// 重置
//
// <Button type="primary" htmlType="submit" loading={submitting} style={{
// marginLeft: 8,
// }}>
// 提交
//
//

叉子的使用姿势

fork [fɔ:k] n. 叉子

Fork 是开源社区每一个参与者的基本权利。为了充分运用这一权利,我们需要了解该权利有哪些使用场景,以及该如何使用,可以先参考 GitHub 官方文档

但其实,除了 GitHub 文档里提到的两种情况,我们还有其他必须 fork 的场景:

  1. 某一依赖发布频率较低,而业务系统中的 bug 需要尽快修复。
  2. 某些改动(bugfix、优化)对我们项目而言很有价值,但该仓库的 maintainer 不接受相应 PR。

这两种情况,都不能只是简单的 fork,还需要考虑原仓库与 fork 仓库之间代码同步的问题。所以,我们需要一个具体的 fork 工作流以规范原仓库与 fork 仓库之间的代码同步行为。

示例

为了方便读者理解,先假设有一个名为 incredible 的仓库,同时 npm 上也有一个同名的包。

现在,我们业务系统中碰到了一个 bug。经排查,问题来自 incredible,然后还找到了修复办法。但问题是,这个 bugfix 需要立刻上线,而 incredible 的 maintaner 并不会立刻合并我们的 PR 并发版本。

这个时候我们就需要 fork incredible 并发布自己的 npm 包。

Fork

下图中,upstream/master 是原仓库最新代码,origin/master 是在 GitHub 上 fork 后自动生成的分支,代码与 upstream/master 同步。然后我们在 origin/master 的基础上再 fork 一个 bugfix 分支 origin/bugfix,并在上面提交了 D 以修复问题。

image

为了尽快的把 bugfix 上线,需要先把 origin/bugfix 的代码发到 npm。这里需要使用一个新的包名,如 @benjycui/incredible。然后在项目中安装 @benjycui/incredible,并通过 webpack 的 resolve.alias 把对 incredible 的引用指向 @benjycui/incredible 即可。

出于开源精神,我们还要把这个 bugfix PR 到 upstream/master 上。如果 maintainer 愿意合并这个 PR,那么只需在 maintainer 发布新版后,安装新版 incredible 并移除 resolve.alias 配置即可。

一切顺利的话,时序图如下:

image

事实上,不可能每件事都称心如意,这个 PR 被拒绝了。现在,我们需要自行维护 @benjycui/incredible。

Merge

在我们把 bugfix D 上线后,incredible 本身也提交了新的 commit E,所以需要把这些新的提交也同步过来,并发布新版 @benjycui/incredible。

image

为了分支名更加明确,把 origin/bugfix 重命名为 origin/incredible。

接上文的时序图,在 PR 被拒绝后,新的时序图如下:

image

Develop

在项目持续迭代的过程中,又碰到了 incredible 的 bug。我们需要先在 origin/incredible 上修复该 bug,新的 bugfix commit 为 F,并发布新版 @benjycui/incredible。

image

虽然 incredible 的 maintainer 之前拒绝了我们的 PR,但我们毕竟是有开源精神的人,所以这次的 bugfix 还会继续 PR 回 incredible。为此我们需要基于 origin/master fork 一个 bugfix 分支 origin/bugfix,并把 F pick 过去。

image

然后继续走普通的 PR 流程把 origin/bugfix PR 到 upstream/master 即可。

本示例完整流程图如下:

image

编写高质量业务组件

本文中以 React 为例,但其中的观点及方法论,对 Vue、Angular 等同样适用。

React 于 2013 开源至今,已经过去了五年。这五年里,前端界从一开始对 HTML in JS(JSX) 等新概念的抗拒,到接受,并且在项目中大量使用。现在,React 已经改变了 View 层的开发方式。

可惜,对于不少人而言,使用 React 也只是改变了他们的开发方式而已。React 所提供的,以组件的方式拆分 View 层代码,并通过组件组合的方式搭建页面,这一基本能力并没有被充分发挥。从我过去三年接触过的 React 项目来看,大多数的开发者(全栈 & 专业前端),只是把组件当做拆分代码的方式,很少会去思考组件该如何设计。结果就是,在项目里随处都能看到组件与 owner 的逻辑、样式强耦合。

在使用了 React 的前提下,项目里却还是一大堆没有正确封装且相互之间高度耦合的组件,相当讽刺(毕竟 React 在 README.md 里面可是强调了 Component-Based),却在意料之中。因为,React 只是降低了组件实现的难度,并没有降低组件设计的难度

为了提高项目的质量,我们需要提高项目中 React 组件的设计质量。如果项目只有一个开发者,事情相对容易,只需要不断地提高个人的组件设计能力,并保持相关意识即可。但对由多人协作开发的项目而言,还需要有相应的开发流程保证,才能全面的提高整个项目的质量,如 ESLint 之于代码风格。

但在介绍相应的方法论之前,得先讨论一个更加基本的问题。

为什么需要设计良好的组件

对于业务线的开发者而言,在组件设计上花费较多的时间,似乎不是一件值得的事情。毕竟业务系统中的组件,往往只有一个使用场景,所以即使组件与其使用场景强耦合,也不是什么罪过。

对一次性项目而言,如活动页,这个论点是对的。但对于需要长期维护的项目而言,一个组件从开发完成,到最终被废弃,它的使用场景其实是不断变化的,因为项目在不断地迭代、重构。例如,C 组件在一开始是在 A 组件下,

image

一段时间后,A 组件被大幅度重构,可以理解为 A 被一个更好的实现 D 替代了,

image

如果 A 与 C 强耦合,那么这次重构将会非常辛苦,C 也需要面临本可以避免的重构。可见,设计良好的组件,能够降低重构的成本。

当然,上面提到的优点是建立在一个组件会被长期使用,随着项目不断迭代的前提下。但前端界面是一个非常不稳定的存在,一个组件被开发出来用不了多久可能就被废弃了,这还有认真设计的必要么?

即使是会被废弃的组件,仍然需要有良好的设计。同样是上面的例子,A 组件被替换为 D 组件后,root 中与 A 相关的代码必然需要调整。如果 root 与 A 强耦合,那么 root 就需要较大的改动,而如果 A 是封装良好的组件,那么 root 中只需要移除 A 相关的 state 与 handler 即可。可见,设计良好的组件,能相对容易的移除、被其他组件替换或替换其他组件

以上。

以下。

在一个隔离的环境中开发组件

与其在开发组件时,时刻堤防着不能与其他组件耦合,还不如直接在一个隔离的环境中开发组件,其实这也是通用组件的开发方式。

为了方便读者理解与实践,接下来会用 Storaybook + DvaJS 展示该方法论。必需强调的是,工具和框架是可以自由选择的。

接入 Storybook

  1. npm install dva-cli -g 安装 dva-cli,然后运行 dva new demo 生成项目目录。
  2. npm i -g @storybook/cli 安装 storybook,然后在 1 创建的项目中运行 getstorybook
  3. 更新 package.json 中的脚本
    {
      "scripts": {
        "storybook": "start-storybook -p 9001 -c .storybook"
      }
    }
  4. 更新 .storybook/config.js 为以下内容
    import { configure } from '@storybook/react';
    
    function loadStories() {
      require('../src/components/stories/Example.js');
    }
    
    configure(loadStories, module);
  5. 创建文件 src/components/stories/Example.js 并写入以下内容
    import React from 'react';
    import { storiesOf } from '@storybook/react';
    import Example from '../Example';
    
    storiesOf('Example', module)
      .add('normal', () => (
        <Example />
      ));

然后就可以通过 npm startnpm run storybook 分别运行项目和 Storybook。

开发流程

引入 Storybook 后,在本地开发时,需要同时运行项目与 Storybook。然后组件的开发、测试工作都先在 Storybook 中完成,再把组件接入项目系统中联调。流程如下:

image

在一个隔离的环境中开发组件,自然就能保证组件不与上层代码耦合。

除了上文提到的优点,引入Storybook 还带来额外的好处:

  1. 组件 debug 会变得简单。
    当一个组件碰到问题时,先尝试在 Storybook 及业务系统中分别重现问题。如果 Storybook 中无法重现,在业务系统中却能重现时,那么问题大概率是在组件的使用方式上。以此类推。
  2. 使用 Storybook 开发组件时编写的 stories 也能成为组件的使用示例,一定程度上缓解了业务代码缺少文档的问题。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.