React Redux の 過剰なコンポーネントアップデートを抑制する方法一覧

React Reduxで作業をしていると、過剰にコンポーネントがアップデートされるシーンがでてくるかもしれません。

アップデート抑制方法は色々ありますが、違いが分かりにくかったため
今回は比較リストを作成しました。

関連：[React Redux の 高負荷なコンポーネントを高速で突き止める](https://qiita.com/EndouT6/items/b90b003ee4fbc80d9e9d)

## コンポーネントのアップデート抑制方法一覧

※ React Reduxのみで実装可能な抑制方法一覧です。

#### class component で制御する場合
| 名前 | 比較方法 |概要|
|---|---|---|
| [pure component](https://qiita.com/EndouT6/items/540ed5859f5fd0165fce#pure-component)| *shallow equal |Propsに変更がなければ component をアップデートしない|
| [shouldComponentUpdate](https://qiita.com/EndouT6/items/540ed5859f5fd0165fce#shouldcomponentupdate)| 手動設定 |shouldComponentUpdate関数で、返り値が false の場合 component をアップデートしない|


#### container component で制御する場合
| 名前 | 比較方法 |概要|
|---|---|---|
| [areStatesEqual](https://qiita.com/EndouT6/items/540ed5859f5fd0165fce#arestatesequal) |strictly equal| Stateに変更がなければ対象のpresentational コンポーネント を呼ばない|
| [areOwnPropsEqual](https://qiita.com/EndouT6/items/540ed5859f5fd0165fce#areownpropsequal) |*shallow equal|mapStateToProps と dispatchStateToProps と mergeProps **以外** に渡される Propsに変更がなければ対象の presentational component を呼ばない |
| [areStatePropsEqual](https://qiita.com/EndouT6/items/540ed5859f5fd0165fce#arestatepropsequal) |*shallow equal|mapStateToPropsで渡される値に変更がなければ対象の presentational component を呼ばない |
| [areMergedPropsEqual](https://qiita.com/EndouT6/items/540ed5859f5fd0165fce#aremergedpropsequal) |*shallow equal|mergePropsで渡される値に変更がなければ対象の presentational component を呼ばない |

##### *shallow equal について
２つのオブジェクトのキーを１つづつ処理し、値を比較していきます。
値が `object`, `function` だった場合は厳密な比較ができず、常に違うものと認識されるため注意

## アップデート抑制方法
### pure component
内部的に Props全てに対し shouldComponentUpdate で比較をしてくれる。
`function`, `object`については一見同じように見えても `===` で `false` となるため注意が必要。

#### 特徴
- class component で使用可能
- 渡される全てのPropsを比較
- shallow equal のため `function`, `object`がPropsに入っていると正確な比較ができない

#### 記述例
 
```jsx

export class HogeComponent extends React.PureComponent {
	// contents
}
```


### shouldComponentUpdate
class componentで制御する際、pure component ではアップデート抑制できない時使います。
その際、比較項目が多くなってしまう時は、Container componentでの制御も考えたほうが良いこともあります。

#### 特徴
- PropsやStateを使用することができ、自由度の高い設定ができる
- class component で使用可能

#### 記述例

```jsx

export class HogeComponent extends React.Component {
	public shouldComponentUpdate(nextProps, nextState) {
		return (
		  this.props.name !== nextProps.name ||
		  this.state.number !== nextState.number
		)
	}
	// contents
}
```

### areStatesEqual
object 同士の比較も可能で現在のstateと次のstateの比較もできます。
stateが変更されたらコンポーネントもアップデートしたい時に最適です。

#### 特徴
- **`object` の比較が可能**
- **そのため複雑で大きなStateも比較できる**
- connect関数の第4引数のoptionで設定
- container component で使用される

#### 記述例
```jsx
connect(
  mapStateToProps,
  mapDispatchToProps,
  null,
  {
    areStatesEqual(next, prev) {
      return next.state === prev.state
    }
  }
)(HogeComponent)
```


### areOwnPropsEqual
presentational component に直接渡されるPropsのみを精査します。
`mapStateToProps` と `mapDispatchToProps` と `mergeProps` で渡される項目は対象外です。

#### 特徴
- mapStateToPropsとmapDispatchToPropsとmergeProps **以外** に渡す値を比較
- connect関数の第4引数のoptionで設定
- container component で使用される
- 比較内容に`function`, `object` がある場合はそれらを避けるように比較する必要がある

#### 記述例
```jsx

connect(
  mapStateToProps,
  mapDispatchToProps,
  null,
  {
    areOwnPropsEqual(next, prev) {
      return next === prev
    }
  }
)(HogeComponent)
```


### areStatePropsEqual
#### 特徴
- mapStateToPropsの値を比較
- connect関数の第4引数のoptionで設定
- container component で主に使用
- shallow equal なので `function`, `object` がある場合はそれらを避けるように比較する必要がある

#### 記述例
```jsx

connect(
  mapStateToProps,
  mapDispatchToProps,
  null,
  {
    areStatePropsEqual(next, prev) {
      return next === prev
    }
  }
)(HogeComponent)
```

### areMergedPropsEqual

#### 特徴
- mergePropsで渡している値を比較
- connect関数の第4引数のoptionで設定
- container component で主に使用
- shallow equal なので `function`, `object` がある場合はそれらを避けるように比較する必要がある

#### 記述例
```jsx

connect(
  state => state,
  dispatch => ({ dispatch }),
  mergeProps,
  {
    areMergedPropsEqual(next, prev) {
      return next === prev
    }
  }
)(HogeComponent)
```


## あとがき

プラグインに頼らないアップデート抑制方法としてこちらを挙げました。

ご指摘箇所あればすぐ直しますのでコメントくださいませ。

最後までお読み頂きありがとうございました。