Airbnb React/JSX 编码范例

来自于Airbnb React/JSX 中文编码范例

Airbnb React/JSX 编码范例

算是最合理的React/JSX编码范例之一了

Basic Rules 基础范例

  • 每一个文件只写一个模块.

  • 引荐运用JSX语法.
  • 不要运用 React.createElement,除非从一个非JSX的文件中初始化你的app.

建立模块

Class vs React.createClass vs stateless

// 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>;
  }
}
假如你的模块没有状况或是没有援用`refs`, 引荐运用一般函数(非箭头函数)而不是类:
// bad
class Listing extends React.Component {
  render() {
    return <div>{this.props.hello}</div>;
  }
}

// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
  <div>{hello}</div>
);

// good
function Listing({ hello }) {
  return <div>{hello}</div>;
}

Naming 定名

  • 扩展名: React模块运用 .jsx 扩展名.
     – 文件名: 文件名运用帕斯卡定名. 如, ReservationCard.jsx.

 – 援用定名: React模块名运用帕斯卡定名,实例运用骆驼式定名. eslint: react/jsx-pascal-case

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

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

// bad
const ReservationItem = <ReservationCard />;

// good
const reservationItem = <ReservationCard />;
  • 模块定名: 模块运用当前文件名一样的称号. 比方 ReservationCard.jsx 应当包含名为 ReservationCard的模块. 然则,假如全部文件夹是一个模块,运用 index.js作为进口文件,然后直接运用 index.js 或许文件夹名作为模块的称号:

    // bad
    import Footer from './Footer/Footer';
    
    // bad
    import Footer from './Footer/index';
    
    // good
    import Footer from './Footer';
  • 高阶模块定名: 关于天生一个新的模块,个中的模块名 displayName 应当为高阶模块名和传入模块名的组合. 比方, 高阶模块 withFoo(), 当传入一个 Bar 模块的时刻, 天生的模块名 displayName 应当为 withFoo(Bar).

为何?一个模块的 displayName 能够会在开发者东西或许错误信息中运用到,因而有一个能清晰的表达这层关联的值能协助我们更好的明白模块发生了什么,更好的Debug.

// bad
export default function withFoo(WrappedComponent) {
  return function WithFoo(props) {
    return <WrappedComponent {...props} foo />;
  }
}

// good
export default function withFoo(WrappedComponent) {
  function WithFoo(props) {
    return <WrappedComponent {...props} foo />;
  }

  const wrappedComponentName = WrappedComponent.displayName
    || WrappedComponent.name
    || 'Component';

  WithFoo.displayName = `withFoo(${wrappedComponentName})`;
  return WithFoo;
}
  • 属性定名: 防止运用DOM相干的属性来用作其他的用处。

为何?关于styleclassName如许的属性名,我们都邑默许它们代表一些特别的寄义,如元素的款式,CSS class的称号。在你的运用中运用这些属性来示意其他的寄义会使你的代码更难浏览,更难保护,而且能够会引起bug。

// bad
<MyComponent style="fancy" />

// good
<MyComponent variant="fancy" />

Declaration 声明模块

  • 不要运用 displayName 来定名React模块,而是运用援用来定名模块, 如 class 称号.

    // bad
    export default React.createClass({
      displayName: 'ReservationCard',
      // stuff goes here
    });
    
    // good
    export default class ReservationCard extends React.Component {
    }

Alignment 代码对齐

  • 遵照以下的JSX语法缩进/花样. eslint: react/jsx-closing-bracket-location

    // bad
    <Foo superLongParam="bar"
         anotherSuperLongParam="baz" />
    
    // good, 有多行属性的话, 新建一行封闭标签
    <Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"
    />
    
    // 若能在一行中显现, 直接写成一行
    <Foo bar="bar" />
    
    // 子元素根据通例体式格局缩进
    <Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"
    >
      <Quux />
    </Foo>

Quotes 单引号照样双引号

  • 关于JSX属性值老是运用双引号("), 其他均运用单引号('). eslint: jsx-quotes

为何? HTML属性也是用双引号, 因而JSX的属性也遵照此商定.

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

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

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

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

Spacing 空格

Props 属性

  • JSX属性名运用骆驼式作风camelCase.

    // bad
    <Foo
      UserName="hello"
      phone_number={12345678}
    />
    
    // good
    <Foo
      userName="hello"
      phoneNumber={12345678}
    />
  • 假如属性值为 true, 能够直接省略. eslint: react/jsx-boolean-value

    // bad
    <Foo
      hidden={true}
    />
    
    // good
    <Foo
      hidden
    />
  • <img> 标签老是增加 alt 属性. 假如图片以presentation(觉得是以相似PPT体式格局显现?)体式格局显现,alt 可为空, 或许<img> 要包含role="presentation". eslint: jsx-a11y/img-has-alt

    // bad
    <img src="hello.jpg" />
    
    // good
    <img src="hello.jpg" alt="Me waving hello" />
    
    // good
    <img src="hello.jpg" alt="" />
    
    // good
    <img src="hello.jpg" role="presentation" />
  • 不要在 alt 值里运用如 “image”, “photo”, or “picture”包含图片寄义如许的词, 中文也一样. eslint: jsx-a11y/img-redundant-alt

为何? 屏幕助读器已把 img 标签标注为图片了, 所以没有必要再在 alt 里说清楚明了.

// bad
<img src="hello.jpg" alt="Picture of me waving hello" />

// good
<img src="hello.jpg" alt="Me waving hello" />
  • 运用有用准确的 aria role属性值 ARIA roles. eslint: jsx-a11y/aria-role

    // bad - not an ARIA role
    <div role="datepicker" />
    
    // bad - abstract ARIA role
    <div role="range" />
    
    // good
    <div role="button" />
  • 不要在标签上运用 accessKey 属性. eslint: jsx-a11y/no-access-key

为何? 屏幕助读器在键盘快捷键与键盘敕令时形成的不统一性会致使浏览性越发庞杂.

// bad
<div accessKey="h" />

// good
<div />
  • 防止运用数组的index来作为属性key的值,引荐运用唯一ID. (为何?)

    // bad
    {todos.map((todo, index) =>
      <Todo
        {...todo}
        key={index}
      />
    )}
    
    // good
    {todos.map(todo => (
      <Todo
        {...todo}
        key={todo.id}
      />
    ))}
  • 关于一切非必需的属性,老是手动去定义defaultProps属性.

为何? propTypes 能够作为模块的文档申明, 而且声明 defaultProps 的话意味着浏览代码的人不需要去假定一些默许值。更主要的是, 显现的声明默许属性能够让你的模块跳过属性范例的搜检.

// bad
function SFC({ foo, bar, children }) {
  return <div>{foo}{bar}{children}</div>;
}
SFC.propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.string,
  children: PropTypes.node,
};

// good
function SFC({ foo, bar }) {
  return <div>{foo}{bar}</div>;
}
SFC.propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.string,
};
SFC.defaultProps = {
  bar: '',
  children: null,
};

Refs

  • 老是在Refs里运用回调函数. eslint: react/no-string-refs

    // bad
    <Foo
      ref="myRef"
    />
    
    // good
    <Foo
      ref={(ref) => { this.myRef = ref; }}
    />

Parentheses 括号

  • 将多行的JSX标签写在 ()里. eslint: react/wrap-multilines

    // 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>;
    }

Tags 标签

  • 关于没有子元素的标签来讲老是本身封闭标签. eslint: react/self-closing-comp

    // bad
    <Foo className="stuff"></Foo>
    
    // good
    <Foo className="stuff" />
  • 假如模块有多行的属性, 封闭标签时新建一行. eslint: react/jsx-closing-bracket-location

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

Methods 函数

  • 运用箭头函数来猎取当地变量.

    function ItemList(props) {
      return (
        <ul>
          {props.items.map((item, index) => (
            <Item
              key={item.key}
              onClick={() => doSomethingWith(item.name, index)}
            />
          ))}
        </ul>
      );
    }
  • 当在 render() 里运用事宜处置惩罚要领时,提早在组织函数里把 this 绑定上去. eslint: react/jsx-no-bind

为何? 在每次 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} />
  }
}
  • 在React模块中,不要给所谓的私有函数增加 _ 前缀,本质上它并非私有的.

为何?_ 下划线前缀在某些言语中通常被用来示意私有变量或许函数。然则不像其他的一些言语,在JS中没有原生支撑所谓的私有变量,一切的变量函数都是共有的。只管你的企图是使它私有化,在之前加上下划线并不会使这些变量私有化,而且一切的属性(包含有下划线前缀及没有前缀的)都应当被视为是共有的。相识更多详情请检察Issue #1024, 和 #490

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

  // other stuff
});

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

  // other stuff
}
  • render 要领中老是确保 return 返回值. eslint: react/require-render-return

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

Ordering React 模块性命周期

  • class extends React.Component 的性命周期函数:
  1. 可选的 static 要领
  2. constructor 组织函数
  3. getChildContext 猎取子元素内容
  4. componentWillMount 模块衬着前
  5. componentDidMount 模块衬着后
  6. componentWillReceiveProps 模块将接收新的数据
  7. shouldComponentUpdate 推断模块需不需要从新衬着
  8. componentWillUpdate 上面的要领返回 true, 模块将从新衬着
  9. componentDidUpdate 模块衬着完毕
  10. componentWillUnmount 模块将从DOM中消灭, 做一些清算使命
  11. 点击回调或许事宜处置惩罚器onClickSubmit()onChangeDescription()
  12. render 里的 getter 要领getSelectReason()getFooterContent()
  13. 可选的 render 要领renderNavigation()renderProfilePicture()
  14. render render() 要领
  • 怎样定义 propTypes, defaultProps, contextTypes, 等等其他属性…

    import React, { PropTypes } from 'react';
    
    const propTypes = {
      id: PropTypes.number.isRequired,
      url: PropTypes.string.isRequired,
      text: PropTypes.string,
    };
    
    const defaultProps = {
      text: 'Hello World',
    };
    
    class Link extends React.Component {
      static methodsAreOk() {
        return true;
      }
    
      render() {
        return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>
      }
    }
    
    Link.propTypes = propTypes;
    Link.defaultProps = defaultProps;
    
    export default Link;
  • React.createClass 的性命周期函数,与运用class稍有差别: eslint: react/sort-comp
  1. displayName 设定模块称号
  2. propTypes 设置属性的范例
  3. contextTypes 设置上下文范例
  4. childContextTypes 设置子元素上下文范例
  5. mixins 增加一些mixins
  6. statics
  7. defaultProps 设置默许的属性值
  8. getDefaultProps 猎取默许属性值
  9. getInitialState 或许初始状况
  10. getChildContext
  11. componentWillMount
  12. componentDidMount
  13. componentWillReceiveProps
  14. shouldComponentUpdate
  15. componentWillUpdate
  16. componentDidUpdate
  17. componentWillUnmount
  18. clickHandlers or eventHandlers like onClickSubmit() or onChangeDescription()
  19. getter methods for render like getSelectReason() or getFooterContent()
  20. Optional render methods like renderNavigation() or renderProfilePicture()
  21. render

isMounted

为何? isMounted 反人类设想形式:(), 在 ES6 classes 中没法运用, 官方将在将来的版本里删除此要领.

    原文作者:Pines_Cheng
    原文地址: https://segmentfault.com/a/1190000008629494
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞