🐷

Vue.jsを知っているが故に、React学習時に詰まりそうなポイント

2022/12/26に公開

業務で四年ほどVue.jsに触れている筆者がReactで簡単なページを作ってみて、
Vue.jsを知っているが故に詰まりそうなポイントをまとめました。
(関数コンポーネントの挙動/useState/useEffectについてです)

想定としては、チュートリアルを読んでhooksにも軽く目を通した人です。

Vue.jsの経験者でReactを学習中の人の助けになると幸いです。

作ったもの

このくらいのアプリを作れる程度にはReactを調べたよということで
作ったものを説明しておきます。

学習するにあたって非同期通信がないのも味気ないので、
WebAPIで値を取得し、結果をU/Iに反映するアプリを作りました。

アプリ
リポジトリ

右下のプラスアイコンをクリックして都市を選ぶと、天気と写真を組み合わせたカードを表示するアプリです。
天気の情報はopen-meteoから取得(fetch)、写真はunsplashからそれっぽいものを引っ張ってきています。

備考

  • ディレクトリ構造はbulletproof-reactを参考
  • Tailwind CSS, ReactQuery使用

ReactHooksとcompositon-api

同じ役割のものがあるのですが挙動はかなり異なります。
Vue.jsと同じ感覚で使うとうまく動きません。

useStateとref

Vue.jsのrefにあたるものとして、useStateがあります。

useState()を呼び出すと値と更新用関数のリストが返ってきます。

const [state, setState] = useState({value: 0});

↑のようなコードであればstateが値、setStateが更新用関数になります。
stateの中身は{value: 0}となっています。

refと異なっている点として、state内部のプロパティを変更しても検知されません。
例えば

state.value = 1;

のような変更が検知されません。

Vue.jsと同じ感覚で使用するとstateのプロパティを変更したはずなのに

  • 再レンダリングが発生せずに表示が切り替わらない
  • useEffect(Vue.jsでのwatch)が処理されない

といったことが起こります。

Reactの関数コンポーネントとVue.jsのsetup関数

関数コンポーネントがピンと来なかった方はここを見てください。
(おそらく名前に馴染みがないだけで目にしたことがあると思います)

Vus.jsでコンポーネントを作成する際に、setup関数の処理でref,computed,watch等々を使用していると思います。

Vue.jsのsetup関数はコンポーネント生成時に一回呼び出されます。
具体的には、refで生成した変数の中身が変わってもsetup関数が呼ばれることはありません。

わざわざこういう書き方をしたのは、useStateで生成した変数が変更されると再び関数コンポーネントの処理が実行されるからです。

上記の動作を簡単に確認できるコンポーネントを用意しました。コピペしてお好みの環境で使ってみてください。

import { useState } from "react";

function MyInput() {
  console.log("MyInput()!")
  const [state, setState] = useState("");
  const onChange = (event) => {
    setState(event.target.value)
  }

  return <input value={state} onChange={onChange}/>;
}

inputタグを生成するコンポーネントです。
文字を入力するとonChangeによりsetStateが呼ばれてstateの値が変更されます。
そのときにMyInput()が呼ばれてログにMyInput()!が出力されるのが確認できます。

これで関数コンポーネントの処理が再呼び出しされることを確認できました。
因みに親コンポーネントから渡された値が変わっても再度呼び出されます。

値が変わるたびに再呼び出しされるとすると疑問が出てきます。
useState()が毎回呼ばれるのでは?呼ばれたら初期化されてしまうのでは?
公式サイトの説明を引用すると、

補足
どうして createState ではなく useState という名前なのか気になるでしょうか?

state が「作成」されるのはコンポーネントの初回レンダー時だけですので、
createState という名前はあまり正確ではありません。
次回以降のレンダー時には、useState からは既存の state の現在値を受け取ります。
毎回作成していたのではそもそも「状態」になりませんね。

とのことで、初回で状態を生成して値を受け取り、以降は現在の値を受け取るという挙動のようです。

computedはない

変更に反応して、useStateでの生成値以外が再計算されることになりますのでuseStateの生成値を加工した値がcomputedに相当することになります。

useEffectとwatch

値の変更を検知して処理を実行するものという点でそこまで違いはないように見えます。(useEffectにはエフェクトのクリーンアップなど特有の機能があるようですが筆者がまだ把握できていません...)

CustomHooksとcomposables

元々、Vue.jsのcomposablesはReactに影響を受けて作られています。(vs. React Hooks)
考え方は流用できますが関数コンポーネントとsetup関数の挙動の違いに気をつける必要があります。

非同期処理にはSuspenseとReactQuery

hooksで非同期処理を実装することもできますが2022年現在ではSuspenseを使った方法が主流のようです。
(Vue.jsにも試験的にSuspenseが追加されています)

Suspenseについて、ReactのSuspense対応非同期処理を手書きするハンズオンがとても参考になりました。
Suspenseの厄介な部分をうまく隠してくれるのがRequestQueryです。(状態管理もしてくれる優れものです。)

まとめ

Vue.jsを知っているが故に詰まりそうなポイントについて書きましたが、どうだったでしょうか。
この辺りを把握していれば、他の記事の内容もわかりやすくなると思います。

Discussion