前端开发代码规范 React 编码规约

基本

1.1

每个文件只写一个组件,但是多个无状态组件可以放在单个文件中。

组件

2.1

【强制】有内部状态,方法或者是要对外暴露ref的组件,使用ES6 Class写法。

// bad
const Listing = React.createClass({
  // ...
  render() {
    return <div>{this.state.hello}</div>;
  }
});

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

2.2

没有内部状态,方法或者是无需对外暴露ref的组件,使用函数写法。

// bad
class Listing extends React.Component {
  render() {
    return <div>{this.props.hello}</div>;
  }
}

// good
const Listing = ({ hello }) => (
  <div>{hello}</div>
);

PropTypes/DefaultProps

3.1

有内部状态,方法或者是要对外暴露ref的组件,使用ES7类静态属性提案写法。

class Button extends Component {
  static propTypes = {
    size: React.PropTypes.oneOf(['large', 'normal', 'small']),
    shape: React.PropTypes.oneOf(['default', 'primary', 'ghost'])
    disabled: React.PropTypes.bool
  };

  static defaultProps = {
    size: 'normal',
    shape: 'default',
    disabled: false
  };

  render() {
    // ....
  }
}

3.2

没有内部状态,方法或者无需对外暴露ref的组件,使用类静态属性写法。

const HelloMessage = ({ name }) => {
  return <div>Hello {name}</div>;
};

HelloMessage.propTypes = {
  name: React.PropTypes.string
};

HelloMessage.defaultProps = {
  name: 'vic'
};

3.3

PropTypes必须。

State

4.1

使用ES7实例属性提案声明写法或者构造函数声明写法,后者适合需要进行一定计算后才能初始化state的情况。

class Some extends Component {
  state = {
    foo: 'bar'
  };

  // ....
}

class Some extends Component {
  constructor(props) {
    super(props);
      this.state = {
        foo: 'bar'
      };
  }

  // ....
}

4.2

【建议】不建议对this.state进行赋值。

// bad
this.state.name = this.props.name.toUpperCase();

// good
this.setState({
  name: this.props.name.toUpperCase();
});

DisplayName

【建议】为了调试方便,建议在组件最上面写displayName。

// good
class Some extends Component {
  static displayName = 'Some';

  // ....
}

命名

5.1

【强制】扩展名: React组件文件使用.jsx扩展名。

5.2

文件名: 文件名使用驼峰式命名,首字母大写,如ReservationCard.jsx

5.3

引用命名: React组件名使用驼峰式命名,首字母大写,实例名也使用驼峰式命名,但首字母小写。

// bad
import reservationCard from './ReservationCard';

// good
import ReservationCard from './ReservationCard';

// bad
const ReservationItem = <ReservationCard />;

// good
const reservationItem = <ReservationCard />;

引号

6.1

对于JSX属性值总是使用双引号", 其他均使用单引号'

// bad
<Foo bar='bar' />

// good
<Foo bar="bar" />

// bad
<Foo style={{ left: "20px" }} />

// good
<Foo style={{ left: '20px' }} />

空格

7.1

【建议】总是在自闭合的标签/>前加一个空格。

// bad
<Foo/>

// very bad
<Foo                 />

// good
<Foo />

7.2

【建议】不要在JSX{}引用括号里两边加空格。

// bad
<Foo bar={ baz } />

// good
<Foo bar={baz} />

7.3

【建议】不要在JSX props属性=两边加空格。

// bad
<Hello name = {firstname} />;

// good
<Hello name={firstname} />;

属性

8.1

【强制】JSX属性名总是使用驼峰式风格。

// bad
<Foo UserName="hello" phone_number={12345678} />

// good
<Foo userName="hello" phoneNumber={12345678} />

8.2

【建议】如果属性值为true, 可以直接省略。

// bad
<Foo hidden={true} />

// good
<Foo hidden />

8.3

【强制】数组中或者遍历中输出相同的React组件,属性key必需。

// bad
[<Hello />, <Hello />, <Hello />];

data.map(x => <Hello>x</Hello>);

// good
[<Hello key="first" />, <Hello key="second" />, <Hello key="third" />];

data.map((x, i) => <Hello key={i}>x</Hello>);

8.4

【强制】class以及for等关键字不允许作为属性名。

// bad
<div class="hello">Hello World</div>;

// good
<div className="hello">Hello World</div>;

8.5

【强制】属性名不允许重复声明。

// bad
<Hello name="John" name="John" />;

// good
<Hello firstname="John" lastname="Doe" />;

Refs

9.1

【强制】总是在Refs里使用回调函数。

// bad
<Foo
  ref="myRef"
/>

// good
<Foo
  ref={ref => { this.myRef = ref; }}
/>

括号

10.1

【建议】将多行的JSX标签写在()里,单行可以省略()

// bad
render() {
  return <MyComponent className="long body" foo="bar">
     <MyChild />
  </MyComponent>;
}

// good
render() {
  return (
    <MyComponent className="long body" foo="bar">
      <MyChild />
    </MyComponent>
  );
}

// good
render() {
  const body = <div>hello</div>;
  return <MyComponent>{body}</MyComponent>;
}

标签

11.1

对于没有子元素的标签来说总是闭合的。

// bad
<Foo className="stuff"></Foo>

// good
<Foo className="stuff" />

方法

12.1

render方法必须有值返回。

// bad
render() {
  (<div />);
}

// good
render() {
  return (<div />);
}

12.2

【建议】按照以下顺序排序内部方法。

1. static methods and properties
2. lifecycle methods: displayName, propTypes, contextTypes, childContextTypes, mixins, statics,defaultProps, constructor, getDefaultProps, getInitialState, state, getChildContext, componentWillMount, componentDidMount, componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, componentDidUpdate, componentWillUnmount (in this order).
3. custom methods
4. render method`

12.3

【建议】不要在componentDidMount以及componentDidUpdate中调用setState,除非是在绑定的回调函数中设置State。

// bad
class Hello extends Component {
  componentDidMount() {
    this.setState({
      name: this.props.name.toUpperCase()
    });
  }
  render() {
    return <div>Hello {this.state.name}</div>;
  }
}

// good
class Hello extends Component {
  componentDidMount() {
    this.onMount(newName => {
      this.setState({
        name: newName
      });
    });
  }
  render() {
    return <div>Hello {this.state.name}</div>;
  }
}

12.4

【建议】使用箭头函数来获取本地变量。

function ItemList(props) {
  return (
    <ul>
      {props.items.map((item, index) => (
        <Item
          key={item.key}
          onClick={() => doSomethingWith(item.name, index)}
        />
      ))}
    </ul>
  );
}

12.5

【建议】当在render()里使用事件处理方法时,提前在构造函数里把this绑定上去。

解释:为什么?在每次render过程中, 再调用bind都会新建一个新的函数,浪费资源。

// bad
class extends React.Component {
  onClickDiv() {
    // do stuff
  }

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

// good
class extends React.Component {
  constructor(props) {
    super(props);

    this.onClickDiv = this.onClickDiv.bind(this);
  }

  onClickDiv() {
    // do stuff
  }

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

12.6

【建议】在React模块中,不要给所谓的私有函数添加_前缀,本质上它并不是私有的。

解释:_下划线前缀在某些语言中通常被用来表示私有变量或者函数。但是不像其他的一些语言,在JS中没有原生支持所谓的私有变量,所有的变量函数都是共有的。尽管你的意图是使它私有化,在之前加上下划线并不会使这些变量私有化,并且所有的属性(包括有下划线前缀及没有前缀的)都应该被视为是共有的。了解更多详情请查看Issue #1024,和#490

// bad
React.createClass({
  _onClickSubmit() {
    // do stuff
  },

  // other stuff
});

// good
class extends React.Component {
  onClickSubmit() {
    // do stuff
  }

  // other stuff
}

参考资料


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343