-
React Hooks がやってくる
- 2019年1月8日
- JavaScript
- React
ここで紹介する機能は アルファ版です(2019年1月現在)。本番環境で運用するプロジェクトにはまだ利用しないでください。
React Hooks
React の新機能 Hooks が話題になっています。
Hooks のメリット
機能追加の背景については Motivation に詳しく書かれていますが、 これまで React には下記のような課題がありました。
- ステートレスなコンポーネント(= 関数型コンポーネント)をステートフルに改修する際、クラス型のコンポーネントにリファクタする必要があった
- リファクタによるコストが大きい
- コンポーネント間でステートフルな情報を共有する(例えば
store
にアクセスする)際、High-Order Component や Provider・Consumer の手法を使う 必要があった- いわゆる “ラッパー地獄” を招いた
Hooks は下記のような特徴を備えることで、上記の課題を解決します。
- 既存のコンポーネント階層を変えることなく、ステートフルなロジックを取り入れる
- あるコンポーネントのステートフルなロジックを 別のコンポーネントに流用できる
基本の使い方
例えば、this.props.count
だけを表示するようなコンポーネント CountViewer
があったとします。
function CountViwer({count}) {
return (
<>Count: {count}</>
);
}
これまで、このコンポーネントにステートをもたせた Counter
コンポーネントへ改修するには、クラスコンポーネントに リファクタする必要がありました。
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: props.initialCount };
}
return (
<>
Count: {count}
<button onClick={() => this.setState({ count: 0 })}>Reset</button>
<button onClick={() => this.setState({ count } => ({ count: count + 1})}>+</button>
<button onClick={() => this.setState({ count } => ({ count: count - 1})}>-</button>
</>
);
}
もはや別物ですね。。
useState
を使うと、こうなります。
import { useState } from 'react';
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(0)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
</>
);
}
関数型コンポーネントに、ステートを注入しています。
概説
useState
は [state, setState]
を返却します。これは、今まで(クラスコンポーネント)の state
と setState
を返却することに相当しますが、 この setState
はペアで返却された state
のみを更新できます。
また、useState
に引数を与えると、state
の初期値となります。 上記の例の場合、(props
として受け取った) initialCount
が初期の count
になります。
初期値を求めるために処理が必要な場合、useState
の引数を関数にすることもできます。 この場合、初期値を関数の返却値にしてください。
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
(Lazy initialization より引用)
useEffect の利用
関数型コンポーネント内で副作用のある処理を直接書くと、バグが発生しやすく、またデータと UI の不一致などを招く恐れがあります。
そのため、副作用は useEffect
を使って注入します。
useEffect(didUpdate);
useEffect
は render
処理が走る度に引数に渡された関数 didUpdate
を呼び出します。
ただ、特定条件下でのみ didUpdate
を呼び出したい場合は、第 2 引数に変更を監視する値を指定します。
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
},
[props.source],
);
(Conditionally firing an effect より引用)
上記のコードでは、props.source
に変更があったときだけ useEffect
内の関数が実行されます。
初回の render
処理時のみ関数を実行させたい場合は、第 2 引数に空の配列 []
を渡してください。
Hooks の制約
Hooks の利用にはいくつか制約があります。
トップレベルで呼び出す必要がある
- ループ内
- 条件式内
- ネストした関数内
で Hooks を呼び出してはいけません。
関数コンポーネント内でのみ呼び出す必要がある
通常の JavaScript 関数内で呼び出しは行わないでください。Hooks は関数型コンポーネント内でのみ利用できます。
まとめ
Hooks は関数型コンポーネントにステートフルなロジックを組み込むための仕組みです。
非常にシンプルな仕組みで実現できる分、様々な応用が可能です。次回以降、発展的な内容も見ていきたいと思います。
この記事を書いた人 : 上田直諒
AWS bluebird css CSV docker docker compose electron ES6 es2015 Git Heroku ITコンサルティング JavaScript justinmind less mongoDB Node.js php PostgreSQL Private Space Promise React react-router reactjs Salesforce scss Selenium Builder selenium IDE Selenium WebDriver stylus TypeScript VirtualBox VisualStudioCode vue vuejs webpack システム開発プロジェクト セキュリティ ワイヤーフレーム 上流工程 卒FIT 帳票 要件定義 設計 電力小売業界