React Hooksの学習第4弾でしょうか。

React案件獲得のためにと思い勉強してきたReactですが、参画予定の案件でNuxtを使うことになるかもとのことです笑

とはいえ自身のスキルセットを広げていきたいし、Reactを学ぶことでVueとの違いを理解できるという利点もあると思うので、今日も今日とて勉強していきました。

useCallbackとは

パフォーマンス向上のためのHook

callback関数(イベントハンドラ)をメモ化する

不要に新しく関数インスタンスを作成することを抑制し、不要な再描画を減らす
→Vueでいうcomputedみたいなもの

依存配列の要素(deps; dependency list)が変化した場合のみメモ化した値を再計算する
→やっぱりVueでいうcomputedみたいなもの

const callback = useCallback(関数, [deps])

なぜuseCallbackを使う?

stateの変更に伴い、他のコンポーネントまで再描画されてしまうから。

useCallback使い方

  1. exportする関数コンポーネントをReact.memo()でラップ
export const Count = React.memo(({text, count}) => {
  console.log('count component -', text)
  return (
    <div>
      {text}: {count}
    </div>
  )
})
  1. useCallbackをインポート

  2. 再描画して欲しくない関数に対してuseCallbackでラップする

const incrementAge = useCallback(
  () => {
    setAge(age + 1)
  },
  [age],
)

上記の例では、ageが変更される時のみincrementAge関数が再発行される

useMemoとは

こちらもuseCallback同様パフォーマンス向上のためのHook

useCallbackとの違い

useCallback
-> 関数自体をメモ化する = 返却値が関数

useMemo
-> 関数の結果を保持する = 返却値が値

useMemoの方がよりvue.computedに近い?

一つ重い処理があると、他の描画に影響を与えてしまう。その影響を受けないようにするためにuseMemoを使って関係のないレンダリング処理に影響を受けないようにする

useMemoの使い方

  1. useMemoをインポート

  2. 重たい関数に対してuseMemoでラップ

const isEven = useMemo(() => {
  let i = 0
  while (i < 200000000) i ++
  return countOne % 2 === 0
}, [countOne])

上記のようにすることで、countOne以外のstateに変更があってもisEvenは再実行されない。
->パフォーマンス改善に寄与できる。

useRefとは

classコンポーネントでいうCreateRefと同等

コンポーネントがレンダリングされてからUnmountされるまでの間、ミュータブルなRefオブジェクトをuseRefは生成する

-> 参照したいDOMなどを持たせたりクロージャー内で宣言された値などへアクセスする場合にuseRefを使ってアクセスできる

useRefの使い方

例1 inputに初期状態でFocusを当てる

  1. useRefをReactからインポート

  2. 関数コンポーネント内でuseRefを用いてrefオブジェクトを生成

const inputRef = useRef(null)
  1. refオブジェクトをinputのrefプロパティに持たせる
<input type="text" ref={inputRef} />
  1. refオブジェクトのcurrentプロパティ内にinputノードが格納され、inputフィールドにアクセスすることが可能となった。
useEffect(() => {
  inputRef.current.focus()
}, [])

useRefによって作成されたオブジェクトはすでにcurrentプロパティを持っており、useRefによって渡された引数が初期値としてcurrentプロパティに格納されている。

例2 1秒ごとにカウントアップする

  1. useEffect内でsetInterval
useEffect(() => {
  const interval = setInterval(() => {
    setCount(prevCount => prevCount + 1)
  }, 1000);
  return () => {
    clearInterval(interval)
  }
}, [])
  1. jsxでストップを作成
<div>
  <h1>{count}</h1>
  <button onClick={() => clearInterval(interval)}>ストップ</button>
</div>

この時、変数intervalはuseEffectのローカル変数であるため、interval is not defiendとしてエラーになる

  1. useRefをインポート、interval変数をrefオブジェクトに書き換え
const intervalRef = useRef()
useEffect(() => {
  intervalRef.current = setInterval(() => {
    setCount(prevCount => prevCount + 1)
  }, 1000);
  return () => {
    clearInterval(intervalRef.current)
  }
}, [])
return (
  <div>
    <h1>{count}</h1>
    <button onClick={() => clearInterval(intervalRef.current)}>ストップ</button>
  </div>
)

intervalRefはcurrentプロパティを持つので、値は.currentに代入する

所感

この数日React Hooksを学習してきましたが、残すところはカスタムフックです。

基礎を身につけても実際に手を動かしてアプリ作成をしていかないと身につかないことも多いと思いますので、今後は何か一つReactアプリケーション作成をしたいと思っています。

当面はまずReactアプリというかGatsby.jsを使った自社ホームページのリニューアルかな、と。

やれる幅が広がっていくのはシンプルに楽しいですね。これからも精進します。