react-components-docs/react编码规范.md

12 KiB
Raw Permalink Blame History

react组件开发规范

要求编码规范,接口定义规范,组件结构自由给予用户充分定制能力。

文件命名

  • 每一个文件只包含一个组件,每一个基本组件只包含单一功能
  • src目录下如果文件返回是一个类文件名首字母大写
  • 文件js模块统一使用js后缀名
  • React组件文件使用大驼峰命名方式其他文件一律使用小写命名如果需要使用中划线分割。

js规范

  • 使用es6开发尽量使用常用的ES6语法ES6语法参考
  • 使用jsx语法

格式

  • 标签自闭合
//bad

<Button></Button>

//good
<Button />
  • 自闭合换行
//bad

 <Button color="primary" />

//good

<Button
    color="primary"
/>

组件命名

  • 组件文件命名使用大驼峰, ComponentDemo
  • 带命名空间的组件如果一个组件包含只有自身使用的子组件以该组件为命名空间编写组件例如TableTable.Head

组件声明

  • 使用es6的class来声明组件而不是使用createClass,在React V16版本createClass已经废弃
// bad
const Button = React.createClass({
  // ...
  render() {
    return <button>{this.state.hello}</button>;
  }
});

// good
class Button extends React.Component {
  // ...
  render() {
    return <button>{this.state.hello}</button>;
  }

  • 对于不包含staterefs的组件建议写成纯函数组件而且建议使用function关键字声明
//bad

class Button extends React.Component{
    render() {
        return (
            <Button>{ this.props.text }</Button>
        )
    }
}

//bad

const Button = ({ text }) => (
    <button>{ text }</button>
 )

//good

function Button ({ text }) {
    return (
        <button>{ text }</button>
    )
}
  • 对于只有简单数据类型的propsstate的组件,建议使用PureComponent来声明组件

//bad

class Button extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            disabled: false
        }
    }
    render() {
        return (
            <Button
                disabled={this.state.disabled}>
            { this.props.text }
            </Button>
        )
    }
}

//good

class Button extends React.PureComponent{
    constructor(props){
        super(props);
        this.state = {
            disabled: false
        }
    }
    render() {
        return (
            <Button
                disabled={this.state.disabled}>
            { this.props.text }
            </Button>
        )
    }
}

组件内部声明

  • 使用propTypes进行props类型校验
import PropTypes from 'prop-types';

const propTypes = {
    disabled: PropTypes.bool
}

class Button extends React.Component{}

Button.propTypes = propTypes;

  • 使用defaultProps定义默认参数
import PropTypes from 'prop-types';

const defaultProps = {
    disabled: false
}

class Button extends React.Component{}

Button.defaultProps = defaultProps;

  • 不使用displayName命名

displayName属性用于组件调试时输出显示JSX自动设置该值可以理解为调试时显示的组件名。

// bad
export default React.createClass({
  displayName: 'Button',
  // stuff goes here
});

// good
export default class Button extends React.Component {
}

属性定义

  • 定义props避开react关键字及保留字常用的props及state定义可参考下表

  • propsstate使用驼峰命名。

  • 不直接修改state

//bad

class Button extends React.Component{
    constructor(props){
       super(props);
       this.state = {
            disabled: false
       }
    }
    handleClick = () => {
        this.state.disabled = true;
        this.setState({
           disabled:  this.state.disabled
        })

    }

    render() {
        return (
            <Button
                disabled={this.state.disabled}>
            { this.props.text }
            </Button>
        )
    }
}

//good

class Button extends React.Component{
    constructor(props){
       super(props);
       this.state = {
            disabled: false
       }
    }
    handleClick = () => {
        let disabled = ture;
        this.setState({
           disabled
        })

    }

    render() {
        return (
            <Button
                disabled={this.state.disabled}>
            { this.props.text }
            </Button>
        )
    }
}

  • 自定义HTML属性使用data-
class Button extends React.Component{

    render() {
        return (
            <Button
                data-name="submit-button">
            { this.props.text }
            </Button>
        )
    }
}


  • 可以使用es6的这种...props语法获取剩下所有属性,但是如果没有必要,尽量不要使用
class Button extends React.Component{

    render() {
    let {onClick, disabled, ...props} = this.props;
        return (
            <Button
                { ...props }>
            { this.props.text }
            </Button>
        )
    }
}

ref

  • 通过ref可以取到组件原生dom对象。使用传入函数function方式来定义ref,不使用字符串定义ref
//bad


class Button extends React.Component{
    constructor(props){
            super(props);
    }
    componentDidMount() {
        this.refs.buttonRef.focus();
    }

    render() {
        return (
            <Button
                ref="buttonRef">
            { this.props.text }
            </Button>
        )
    }
}

//good

class Button extends React.Component{
    constructor(props){
        super(props);
        this.buttonRef = {};
    }
    componentDidMount() {
        this.buttonRef.focus();
    }

    render() {
        return (
            <Button
                ref={(el) => this.buttonRef = el;}>
            { this.props.text }
            </Button>
        )
    }
}

  • 尽量少或者不使用ref获取和操作dom节点使用state和prop进行控制dom

组件声明周期函数

  • 组件方法定义顺序

    • constructor
    • getChildContext
    • componentWillMount
    • componentDidMount
    • componentWillReceiveProps
    • shouldComponentUpdate
    • componentWillUpdate
    • componentDidUpdate
    • componentWillUnmount
  • componentDidMount生命周期内获取初始数据

class Button extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            data: ''
        }
    }
    componentDidMount() {
        axios.get('http://baidu.com/button-name')
            .then((res) => {
                this.setState({
                    datares.data
                })
            })
    }

    render() {
        return (
            <Button>
            { this.state.data }
            </Button>
        )
    }
}

  • 在组件componentWillUnmount卸载生命周期中,进行清除定时器、卸载组件绑定的自定义事件等。
class Button extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            data: ''
        }
        this.timer = null;
    }
    componentDidMount() {
        this.timer = setInterval(this.getData, 1000);
    }

    getData = () => {
            axios.get('http://baidu.com/button-name')
                .then((res) => {
                    this.setState({
                        datares.data
                    })
                })
    }

    componentWillUnmount() {
        window.clearInterval(this.timer);
    }

    render() {
        return (
            <Button>
            { this.state.data }
            </Button>
        )
    }
}
  • 使用箭头函数定义自定义的组件内方法
//bad
class Button extends React.Component{
    handleClick(e) {

    }
    render() {
        return (
            <Button onClick={this.handleClick.bind(this)}>
            { this.state.data }
            </Button>
        )
    }
}


//good

class Button extends React.Component{
    handleClick = (e) => {

    }
    render() {
        return (
            <Button onClick={this.handleClick}>
            { this.state.data }
            </Button>
        )
    }
}

Mixin

  • 使用es6后不支持mixin使用decorator进行扩展和高阶组件方式扩展。

  • 代码规范使用 airbnb规范

样式规范

  • 组件样式使用sass编写公用样式使用tinper-bee-core包请阅读tinper-bee-core文档
  • 组件样式调用使用classnames模块进行样式处理使用className调用
  • 所有组件默认类名命名以`u-``开头
  • 组件使用clsPrefix为样式前缀,用户也可在组件上设置自定义的clsPrefix="yourPre"
const clsPrefix = 'u-select';
const class1 = {
    [`${clsPrefix}-item`]: true,
    [`${clsPrefix}-item-last`]: stepLast,
    [`${clsPrefix}-status-${status}`]: true,
    [`${clsPrefix}-custom`]: icon
  };
const class2 = [`${clsPrefix}-submit`, `${clsPrefix}-item`];

const classString = classNames('hide', class1, class2);

  • 可提供多种颜色的组件在写scss文件时颜色设置需提出公用的minxin方法例如Alert组件中设置多种颜色 @alert-styles-variant

通用组件接口规范

参数 说明 类型 默认值
size 尺寸 string medium
color 颜色 string ''
shape 形状 string ''
disabled 是否禁用(disabledtrue false) bool false
className 增加额外的类名 string ''
htmlType html dom 的 type 属性 string ''
style 内联样式 object ''
clsPrefix 自定义样式前缀 string ''

对于方法的传递外部使用onClick传入事件内部使用handleClick进行接收使用

国际化

当你的组件包含一些文字时在src目录下创建i18n.js文件写下对应的hash值。内容如下

module.exports = {
    'zh-cn': {
        'ok': '确定',
        'cancel': '取消',
        'isee': '知道了'
    },
    'en-us': {
        'ok': 'ok',
        'cancel': 'cancel',
        'isee': 'ok'
    }
}

组件内这么使用:

import i18n from './i18n';
import React from 'react';

Example.defaultProps = {
    locale: 'zh-cn'
};

class Example extends React.Component {
    constructor(props) {
        super(props);
    }


    render() {
        const {locale} = this.props;
        const locale = i18n[locale];

        const buttons= [
            <Button>
                {locale['ok']}
            </Button>,
            <Button>
                {locale['cancel']}
            </Button>
        ];
        return (
            <div>
            { buttons }
            </div>
            )
    }
}


基本代码结构

//引入依赖
import React from 'react';
import ReactDOM from'react-dom';
import classnames from 'classnames';

//定义prop检验
const propTypes = {
//每一个props都要写注释
}

//定义默认参数
const defaultProps = {

}

/**
 * 定义组件
 */
class Button extends React.Component {
	constructor (props) {
		super(props);
		//定义state
		this.state = {
    //每一个state要写注释
		}
		// 事先声明方法绑定
		this.MyEvent = this.MyEvent.bind(this);
	}

    //自定义函数方法,及注释
      MyEvent () {

      }
    //组件生命周期方法


	render () {
		return (
			// <div onClick={this.MyEvent}></div>
		)
	}
}

Button.propTypes = propTypes;
Button.defaultProps = defaultProps;

export default Button;

常用npm包

keyCode
warning
var warning = require('warning');

var ShouldBeTrue = false;

warning(
  ShouldBeTrue,
  'This thing should be true but you set to false. No soup for you!'
);
bee-animate
bee-overlay
dom-helpers (3.0.0)

参考链接 https://github.com/react-component/react-component.github.io/blob/master/docs/zh-cn/code-style/js.md