[翻訳] Airbnb React/JSX Style Guide


<!--
参照した最後のコミット
- [eslint config] [patch] Fixed handle and on ordering in `sort-com…
- https://github.com/airbnb/javascript/commit/d3c7b84d9e513fc1388de28775574ed614ee33e6
- committed on 23 Sep 2020

参照先の更新履歴
- https://github.com/airbnb/javascript/commits/master/react/README.md
-->

# この翻訳について
[Airbnb React/JSX Style Guide](https://github.com/airbnb/javascript/tree/master/react)の和訳です。
間違っていたり分かりにくい箇所があれば、ご指摘いただけると幸いです。

# Airbnb React/JSX スタイルガイド
このスタイルガイドは現在一般的に使用されている標準に基いていますが、場合によってはいくつかの慣例（async/awaitやstatic class fields）が含まれていたり禁止されていたりします。現在、このガイドにはステージ3より前のものは含まれておらず非推奨です。

## 目次

  1. [基本的なルール](#基本的なルール)
  1. [クラス vs `React.createClass` vs ステートレス](#クラス-vs-reactcreateclass-vs-ステートレス)
  1. [ミックスイン](#ミックスイン)
  1. [命名規則](#命名規則)
  1. [宣言](#宣言)
  1. [アラインメント](#アラインメント)
  1. [引用符](#引用符)
  1. [空白](#空白)
  1. [引数](#引数)
  1. [参照](#参照)
  1. [括弧](#括弧)
  1. [タグ](#タグ)
  1. [メソッド](#メソッド)
  1. [順序](#順序)
  1. [`isMounted`](#ismounted)



## 基本的なルール
- Reactコンポーネントは1ファイルに1つだけにしてください。
	- ただし、1ファイルに複数の[ステートレス](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions)なコンポーネントを含むのは良いです。(eslint: [`react/no-multi-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless))
- 常にJSXの構文を使用してください。
- JSXでないファイルでアプリを初期化している場合を除き、`React.createElement`は使用しないでください。
- [`react/forbid-prop-types`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md)は、`arrayOf`、`objectOf`、または`shape`を使用して`array`および`object`に含まれるかが明示的に示されている場合にのみ、`arrays`と`objects`を許可します。


## <div id="article-anchor-class-vs-reactcreateclass-vs-stateless">クラス vs `React.createClass` vs ステートレス</div>
- stateやrefsを使う場合、`React.createClass`よりも`class extends React.Component`が好まれます。(eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md))

```jsx
// 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を使わない場合、クラスよりも通常の関数(アロー関数ではない) が好まれます。

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



## <div id="article-anchor-mixins">ミックスイン</div>

- [ミックスインは使用しないでください。](https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html)

> ミックスインは暗黙の依存関係により、名前の衝突を引き起こし、雪だるま式に複雑になります。ミックスインの使用事例のほとんどは、コンポーネント、高次コンポーネント、またはユーティリティモジュールを介して、より良い方法で実装できます。



## <div id="article-anchor-naming">命名規則</div>
- **拡張子**: `.jsx`を使用してください。(eslint: [`react/jsx-filename-extension`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md))
- **ファイル名**: パスカルケースを使用してください。(例: `ReservationCard.jsx`)
- **参照名**: Reactコンポーネントにはパスカルケースを使用し、それらのインスタンスにはキャメルケースを使用してください。(eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md))

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

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

// bad
const ReservationItem = <ReservationCard />;

// good
const reservationItem = <ReservationCard />;
```

- **コンポーネントの命名規則**: コンポーネント名としてファイル名を使ってください。例えば、`ReservationCard.jsx`は、`ReservationCard`という参照名を持つ必要があります。ただし、ディレクトリのルートコンポーネントの場合は、ファイル名として`index.jsx`を使用し、コンポーネント名としてディレクトリ名を使ってください。

```jsx
// bad
import Footer from './Footer/Footer';

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

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

- **高次コンポーネントの命名規則**: 高次コンポーネントの名前と渡されたコンポーネントの名前を合わせたものを、生成されたコンポーネントの`displayName`として使用します。例えば、高次コンポーネント`withFoo（）`がコンポーネント`Bar`を渡すとき、`displayName`が`withFoo（Bar）`のコンポーネントを生成すべきです。

> コンポーネントの`displayName`は開発者ツールやエラーメッセージで使用され、この関係をはっきりと示す値を持つことで、何が起こっているのかを理解するのに役立ちます。

```jsx
// 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コンポーネントの引数名を使用しないでください。

> 一般的に`style`や`className`のような引数は、特定のものを意味すると考えます。アプリのサブセットに対してこのAPIを変更すると、コードの読みやすさと保守性が低下し、バグが発生する可能性があります。

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

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

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



## <div id="article-anchor-declaration">宣言</div>
- コンポーネントの命名に`displayName`は使わないでください。代わりに、参照によってコンポーネントに命名してください。

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

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



## <div id="article-anchor-alignment">アラインメント</div>
- 以下の形式に従ってください。(eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md))

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

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

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

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

// bad
{showButton &&
  <Button />
}

// bad
{
  showButton &&
    <Button />
}

// good
{showButton && (
  <Button />
)}

// good
{showButton && <Button />}

// good
{someReallyLongConditional
  && anotherLongConditional
  && (
    <Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"
    />
  )
}

// good
{someConditional ? (
  <Foo />
) : (
  <Foo
    superLongParam="bar"
    anotherSuperLongParam="baz"
  />
)}
```



## <div id="article-anchor-quotes">引用符</div>
- JSXの引数にはダブルクオート(`"`)を使用し、その他のJSにはシングルクオート(`'`)を使用してください。(eslint: [`jsx-quotes`](https://eslint.org/docs/rules/jsx-quotes))

> 通常のHTMLの属性は一般的にシングルクオートの代わりにダブルクオートを使用するため、JSXの属性もこの慣習に倣っています。

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

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

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

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



## <div id="article-anchor-spacing">空白</div>

- 空要素のタグの中にはスペースを１つ入れてください。(eslint: [`no-multi-spaces`](http://eslint.org/docs/rules/no-multi-spaces), [`react/jsx-tag-spacing`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md))

```jsx
// bad
<Foo/>

// very bad
<Foo                 />

// bad
<Foo
 />

// good
<Foo />
```

- JSXの中括弧の中にはスペースは入れないでください。(eslint: [`react/jsx-curly-spacing`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md))

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

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



## <div id="article-anchor-props">引数</div>

- 引数名はキャメルケースを使用し、引数がReactコンポーネントの場合はパスカルケースを使用してください。

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

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

- 引数の値が明らかに`true`である場合には省略してください。(eslint: [`react/jsx-boolean-value`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md))

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

// good
<Foo
  hidden
/>

// good
<Foo hidden />
```

- `<img>`タグには`alt`引数を含めてください。もし、画像が表現的なコンテンツである場合、`alt`を空の文字列するか、`role="presentation"`を含めてください。(eslint: [`jsx-a11y/alt-text`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/alt-text.md))

```jsx
// 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`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md))

> スクリーンリーダーは`img`要素を既に画像として知らせているので、altテキストにこの情報を含める必要がありません。

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

// good
<img src="hello.jpg" alt="Me waving hello" />
```

- 有効で非抽象的な[ARIA roles](https://www.w3.org/TR/wai-aria/roles#role_definitions)のみ使用してください。(eslint: [`jsx-a11y/aria-role`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md))

```jsx
// bad - ARIA roleでない
<div role="datepicker" />

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

// good
<div role="button" />
```
- 要素に`accessKey`を使わないでください。(eslint: [`jsx-a11y/no-access-key`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md))

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

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

// good
<div />
```


- 配列のインデックスを`key`引数に使うのは避けてください。一意のIDが好まれます。(eslint: [`react/no-array-index-key`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md))
> 安定したIDを使用しないと、パフォーマンスに悪影響を及ぼし、コンポーネントのstateに問題が生じる可能性があるため[アンチパターン](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318)です。

要素の順序が変わる可能性がある場合は、keyにindexを使用することはおすすめできません。

```jsx
// bad
{todos.map((todo, index) =>
  <Todo
    {...todo}
    key={index}
  />
)}

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

- 必須ではないすべての引数に対して常に明示的な`defaultProps`を定義してください。

> `propTypes`はドキュメントの一種であり、`defaultProps`を提供するということは、あなたのコードの読者がそれほど多くを引き受ける必要がないことを意味します。また、コードで特定の型チェックを省略することもできます。

```jsx
// 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, children }) {
  return <div>{foo}{bar}{children}</div>;
}
SFC.propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.string,
  children: PropTypes.node,
};
SFC.defaultProps = {
  bar: '',
  children: null,
};
```

  - スプレッド構文の使用は控えてください。

> そうでなければ、不要な引数をコンポーネントに渡す可能性が高まります。React v15.6.1以下では、[無効なHTML属性を渡すことができます](https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html)。

例外：

  - 引数を渡しpropTypesを巻き上げるプロキシとしてのHOC。

```jsx
function HOC(WrappedComponent) {
  return class Proxy extends React.Component {
    Proxy.propTypes = {
      text: PropTypes.string,
      isLoading: PropTypes.bool
    };

    render() {
      return <WrappedComponent {...this.props} />;
    }
  }
}
```

  - 明確な引数とオブジェクトのスプレッド構文。これはMochaのbeforeEachを使ってReactコンポーネントをテストする際に便利です。

```jsx
export default function Foo {
  const props = {
    text: '',
    isPublished: false
  }

  return (<div {...props} />);
}
```

使用上の注意：
可能であれば不要な引数は取り除いてください。またバグを防ぐため[prop-types-exact](https://www.npmjs.com/package/prop-types-exact)を使用してください。

```jsx
// bad
render() {
  const { irrelevantProp, ...relevantProps } = this.props;
  return <WrappedComponent {...this.props} />
}

// good
render() {
  const { irrelevantProp, ...relevantProps } = this.props;
  return <WrappedComponent {...relevantProps} />
}
```

## <div id="article-anchor-refs">参照</div>
- 常に参照コールバックを使用してください。(eslint: [`react/no-string-refs`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md))

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

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



## <div id="article-anchor-parentheses">括弧</div>
- JSXのタグが複数行になる場合は括弧で囲ってください。(eslint: [`react/jsx-wrap-multilines`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-wrap-multilines.md))

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

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

// good - 一行なので
render() {
  const body = <div>hello</div>;
  return <MyComponent>{body}</MyComponent>;
}
```



## <div id="article-anchor-tags">タグ</div>
- 子要素がない場合は以下のように記述してください。(eslint: [`react/self-closing-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md))

```jsx
// bad
<Foo variant="stuff"></Foo>

// good
<Foo variant="stuff" />
```
- 複数行の引数を持つコンポーネントの場合、新しい行でタグを閉じてください。(eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md),  [`react/jsx-closing-tag-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-tag-location.md))

```jsx
// bad
<Foo
  bar="bar"
  baz="baz" />

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



## <div id="article-anchor-methods">メソッド</div>

- ローカル変数を閉じるようにアロー関数を使用してください。追加のデータをイベントハンドラーに渡す必要がある場合に便利です。ただし、特にPureComponentsである可能性のあるカスタムコンポーネントに渡される場合は、[パフォーマンスが大幅に低下しないように](https://www.bignerdranch.com/blog/choosing-the-best-approach-for-react-event-handlers/)してください。なぜなら、毎回不必要な再レンダリングをトリガーするためです。

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

- コンストラクタ内では、renderメソッドに対してイベントハンドラをバインドしてください。 (eslint: [`react/jsx-no-bind`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md))

> render内でのバインドは、レンダリングのたびに新しい関数を作成してしまいます。クラスのフィールドでアロー関数を使用しないでください。[テストとデバッグが難しくなり、パフォーマンスに悪影響を及ぼす可能性があります](https://medium.com/@charpeni/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think-3b3551c440b1)。概念的には、クラスのフィールドはロジック用ではなくデータ用です。

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

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

// very bad
class extends React.Component {
  onClickDiv = () => {
    // do stuff
  }
  render() {
    return <div onClick={this.onClickDiv} />
  }
}

// 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コンポーネントのメソッドにアンダースコアの接頭辞を使わないでください。

> アンダースコアのプレフィックスは、privateを示すために他の言語の規約として使用されることがあります。しかし、これらの言語とは異なり、JavaScriptではprivateのネイティブサポートはなく、すべてがpublicです。あなたの意図にかかわらず、あなたのプロパティにアンダースコアのプレフィックスを追加しても、それを実際にprivateにするわけではなく、任意のプロパティ（アンダースコアのプレフィックス付きかどうか）をpublicとして扱うべきです。詳細は、[#1024](https://github.com/airbnb/javascript/issues/1024)、[#490](https://github.com/airbnb/javascript/issues/490)を参照してください。

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

  // other stuff
});

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

  // other stuff
}
```

- `render`メソッドでは値を返すようにしてください。(eslint: [`react/require-render-return`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md))

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

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



## <div id="article-anchor-ordering">順序</div>
- `class extends React.Component`用の順序

  1. 任意の`static`メソッド
  1. `constructor`
  1. `getChildContext`
  1. `componentWillMount`
  1. `componentDidMount`
  1. `componentWillReceiveProps`
  1. `shouldComponentUpdate`
  1. `componentWillUpdate`
  1. `componentDidUpdate`
  1. `componentWillUnmount`
  1. `onClickSubmit()`、`onChangeDescription()`のような*クリックハンドラまたはイベントハンドラ*
  1. `handleSubmit()`、`handleChangeDescription()` のように *handle で始まるイベントハンドラ*
  1. `onClickSubmit()`、`onChangeDescription()` のように *on で始まるイベントハンドラ*
  1. `getSelectReason()`、`getFooterContent()`のような*`render`用のゲッターメソッド*
  1. `renderNavigation()`、`renderProfilePicture()`のような*任意のレンダリングメソッド*
  1. `render`


- `propTypes`、`defaultProps`、`contextTypes`などの定義方法

```jsx
import React from 'react';
import PropTypes from 'prop-types';

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`用の順序。(eslint: [`react/sort-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md))

  1. `displayName`
  1. `propTypes`
  1. `contextTypes`
  1. `childContextTypes`
  1. `mixins`
  1. `statics`
  1. `defaultProps`
  1. `getDefaultProps`
  1. `getInitialState`
  1. `getChildContext`
  1. `componentWillMount`
  1. `componentDidMount`
  1. `componentWillReceiveProps`
  1. `shouldComponentUpdate`
  1. `componentWillUpdate`
  1. `componentDidUpdate`
  1. `componentWillUnmount`
  1. `onClickSubmit()`、`onChangeDescription()`のような*クリックハンドラまたはイベントハンドラ*
  1. `getSelectReason()`、`getFooterContent()`のような*`render`用のゲッターメソッド*
  1. `renderNavigation()`、`renderProfilePicture()`のような*任意のレンダリングメソッド*
  1. `render`



## <div id="article-anchor-ismounted">`isMounted`</div>

- `isMounted`は使わないでください。(eslint: [`react/no-is-mounted`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md))

> [`isMounted`はアンチパターン](https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html)であり、ES6では使用できず、今後正式に廃止される予定です。