React hooksのuseStateにコールバックをセットするには


React 16.8でReact hooksが導入されて久しい。

いまとなってはステートレスコンポーネントがReactコンポーネント作成のデファクトスタンダードになっている。すでにいくつかのクラスコンポーネントのライフサイクルは非推奨になっているものもある。

React hooksの導入に際して、まず接点があるであろうメソッドはuseState()だろうか。これはthis.setState() として状態を更新していたもののhook版と認識してもらえればよい。馴染みのあるthis.setState()とReact hooksのuseState()は、使いどころこそはおよそ同じであるが、this.setState()にできて、useState()にできないこともある。

それはコールバックの定義だ。

このエントリーでは、ステートレスコンポーネントにおける状態更新のコールバックについて共有したい。

まず、クラスコンポーネントは?

ステートレスコンポーネントにおけるコールバックを示す前に、クラスコンポーネントの例を確認してもらおう。クラスコンポーネントであるから、もちろんthis.setState()だ。

this.setState({
  isVisible: true 
}, () => {
  console.log('ステートが更新された。');
});

this.setState()の第一引数がステートオブジェクト、第二引数がコールバック関数だ。この例では、無名関数を定義しているが、任意の関数をセットできる。

では、ステートレスコンポーネントだと?

前述したとおり、useState()だとコールバックを定義できない。useState()は、状態値の定義と状態を更新するための関数を分割代入するだけのもので、this.setState()のようにコールバックを定義する機能は備わっていない。ではステートレスコンポーネントで状態が更新されたことを捕捉するにはどうしたらよいのだろう。

ステートレスコンポーネントの場合は、React hooksのuseEffect()を使う。

useEffect()は、ライフサイクルのcomponentDidMountやcomponentDidUpdate、componentWillUnmountに類似したものと認識してもらえればよい。

componentDidUpdateライフサイクルでは、現在のステートと更新されるステートを比較して何らかの処理を実行するような場合に使っていた。useState()でもこれを再現させれば良さそうだ。

const [isVisible, setIsVisible] = useState(true);
useEffect(() => {
  console.log('ステートが更新された。');
}, [isVisible]);

useEffect()の第二引数に[isVisible]を渡している。これは現在のステートと更新されるステートを比較して、もし同値であればuseEffect()の第一引数の無名関数をスキップするというものだ。

果たして、ステート更新のコールバックを再現することができた。

まとめ

ステートレスコンポーネントにおける状態更新のコールバックに関する共有だった。

useEffect()の第二引数に渡したステート変数を観測することで、コールバック関数を再現したわけだが、このソースコードの例では、コンポーネントがマウントされたタイミングでも実行されてしまうはずだ。そのようなときは無名関数内でステート値を厳密にチェックするようにしてほしい。

このたび言及した方法のほかに「use-state-with-callback」なるパッケージがあるようで、これでもコールバックができるらしい。わたしは試していないが、期待した機能は保有している様子だ。トライしてみても良いだろう。


Leave a Reply

Your email address will not be published. Required fields are marked *