[翻訳] Airbnb React/JSX Style Guide

  • 460
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

この翻訳について

Airbnb React/JSX Style Guideの和訳です。
間違っていたり分かりにくい箇所があれば、ご指摘いただけると幸いです。

Airbnb React/JSX スタイルガイド

目次

  1. 基本的なルール
  2. クラス vs React.createClass vs ステートレス
  3. 命名規則
  4. 宣言
  5. アラインメント
  6. 引用符
  7. 空白
  8. 引数
  9. 参照
  10. 括弧
  11. タグ
  12. メソッド
  13. 順序
  14. isMounted

基本的なルール

  • Reactコンポーネントは1ファイルに1つだけにしてください。
  • 常にJSXの構文を使用してください。
  • JSXでないファイルでアプリを初期化している場合を除き、React.createElementは使用しないでください。

クラス vs React.createClass vs ステートレス

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

また、stateやrefsを使わない場合、クラスよりも通常の関数(アロー関数ではない) が好まれます。

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

// bad - 関数名の推測が必要となる
const Listing = ({ hello }) => (
  <div>{hello}</div>
);

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

命名規則

  • 拡張子: .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.jsxを使用し、コンポーネント名としてディレクトリ名を使ってください。
// bad
import Footer from './Footer/Footer';

// bad
import Footer from './Footer/index';

// good
import Footer from './Footer';

宣言

  • コンポーネントの命名にdisplayNameは使わないでください。代わりに、参照によってコンポーネントに命名してください。
// bad
export default React.createClass({
  displayName: 'ReservationCard',
  // stuff goes here
});

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

アラインメント

// bad
<Foo superLongParam="bar"
     anotherSuperLongParam="baz" />

// good
<Foo
  superLongParam="bar"
  anotherSuperLongParam="baz"
/>

// 一行に収まるならば、その行にまとめてください
<Foo bar="bar" />

// 子要素はインデントを付けます
<Foo
  superLongParam="bar"
  anotherSuperLongParam="baz"
>
  <Quux />
</Foo>

引用符

  • JSXの引数にはダブルクオート(")を使用し、その他のJSにはシングルクオートを使用してください。(eslint: jsx-quotes)

JSXはエスケープ引用符を含めることができないので、ダブルクオートは"don't"のような接続詞を簡単に入力できるようにします。
通常のHTMLの属性は一般的にシングルクオートの代わりにダブルクオートを使用するため、JSXの属性もこの慣習に倣っています。

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

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

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

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

空白

  • 空要素のタグの中にはスペースを1つ入れてください。
// bad
<Foo/>

// very bad
<Foo                 />

// bad
<Foo
 />

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

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

引数

  • 引数名はキャメルケースを使ってください。
// bad
<Foo
  UserName="hello"
  phone_number={12345678}
/>

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

// good
<Foo
  hidden
/>
  • <img>タグにはalt引数を含めてください。もし、画像が表現的なコンテンツである場合、altを空の文字列するか、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" />
  • <img>alt引数には、"image"、"photo"、"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" />
// bad - ARIA roleでない
<div role="datepicker" />

// bad - 抽象的なARIA role
<div role="range" />

// good
<div role="button" />

スクリーンリーダーやキーボードを使う人々が使用するキーボードショートカットとキーボードコマンド間の不一致は、アクセシビリティを複雑にしてしまいます。

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

// good
<div />
  • 配列のインデックスをkey引数に使うのは避けてください。一意のIDが好まれます。(理由)
// bad
{todos.map((todo, index) =>
  <Todo
    {...todo}
    key={index}
  />
)}

// good
{todos.map(todo => (
  <Todo
    {...todo}
    key={todo.id}
  />
))}

参照

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

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

括弧

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

タグ

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

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

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

メソッド

  • ローカル変数を閉じるようにアロー関数を使用してください。
function ItemList(props) {
  return (
    <ul>
      {props.items.map((item, index) => (
        <Item
          key={item.key}
          onClick={() => doSomethingWith(item.name, index)}
        />
      ))}
    </ul>
  );
}
  • コンストラクタ内では、renderメソッドに対してイベントハンドラをバインドしてください。

render内でのバインドは、レンダリングのたびに新しい関数を作成してしまいます。

// 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コンポーネントのメソッドにアンダースコアの接頭辞を使わないでください。
// bad
React.createClass({
  _onClickSubmit() {
    // do stuff
  },

  // other stuff
});

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

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

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

順序

  • class extends React.Component用の順序
  1. 任意のstaticメソッド
  2. constructor
  3. getChildContext
  4. componentWillMount
  5. componentDidMount
  6. componentWillReceiveProps
  7. shouldComponentUpdate
  8. componentWillUpdate
  9. componentDidUpdate
  10. componentWillUnmount
  11. onClickSubmit()onChangeDescription()のようなクリックハンドラまたはイベントハンドラ
  12. getSelectReason()getFooterContent()のようなrender用のゲッターメソッド
  13. renderNavigation()renderProfilePicture()のような任意のレンダリングメソッド
  14. render
  • propTypesdefaultPropscontextTypesなどの定義方法
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;
  1. displayName
  2. propTypes
  3. contextTypes
  4. childContextTypes
  5. 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. onClickSubmit()onChangeDescription()のようなクリックハンドラまたはイベントハンドラ
  19. getSelectReason()getFooterContent()のようなrender用のゲッターメソッド
  20. renderNavigation()renderProfilePicture()のような任意のレンダリングメソッド
  21. render

isMounted

isMountedはアンチパターンであり、ES6では使用できず、今後正式に廃止される予定です。