見出し画像

Reactのフックの種類について

今回はReact開発における重要項目である、フックについて種類ごとにその働きについてまとめていきます。


useState

記述の仕方

import { useState } from 'react'

const Hooks = () => {
    const [count, setCount] = useState(0)

    const handleClick = () => {
        setCount(count + 1)
    }

  return (
    <div>
        <button onClick={handleClick}>カウント</button>
        <div>{count}</div>    
    </div>
  )
}

export default Hooks

説明

useStateは状態(state)を保存するフックです。普通のJavaScriptの記述であれば、変数としてcountを定義し、handleClick関数のハンドラとしてcountをインクリメントすればカウントは増えていきます。

しかし、Reactは変数が書き換えられてもその様子は画面に反映されません。それは変数の値が変化してもそれを検知しないためレンダリングされないからです。

そこでuseStateを使います。stateを格納する変数とその変数を更新するset関数を配列としてuseStateを定義します。この際、set関数の名前は「set変数名(頭文字が大文字)」と命名するのが基本です。
また、引数には変数の初期値を定義します。

上記の例では、useStateで変数を定義してhandleClick関数のハンドラに同じく定義したset関数を用意します。set関数のハンドラに更新させたいロジックを設定し(定数でも可)したら、set関数が呼び出されたタイミングで変数の状態が変化し、それをReactが検知してレンダリングされます。
これによってカウントが増えていくという流れになります。

useEffect

記述の仕方

import { useState, useEffect } from 'react'

const Hooks = () => {
    const [count, setCount] = useState(0)

    const handleClick = () => {
        setCount(count + 1)
    }

    useEffect(() => {
      console.log(`カウント回数は ${count} 回です。`)
    },[count])

  return (
    <div>
        <button onClick={handleClick}>カウント</button>
        <div>{count}</div>    
    </div>
  )
}

export default Hooks

説明

useEffectは別名副作用フックと言われており、コンポーネントの状態の変化を検知して処理を定義することができるものです。

useEffectは処理を実行するものなので、引数にはアロー関数を定義します。
また、第2引数には配列を用意します。この配列にはuseEffectの発火が依存す変数を定義します。わかりやすく言うと、この配列に格納した変数が変化したタイミングで処理を実行させることができるということです。

上記の例では、countが変化したタイミングでコンソールにカウント回数を表示させたい(useEffectの発火のタイミングをcountが変化したタイミングにしたい)ので、配列にcountを定義しています。また依存する変数を複数定義することも可能です。

この際、空の配列を定義した場合は依存する変数が存在しないため、コンポーネントのマウント時に一度だけ発火します。また、この第2引数を定義しなかった場合、予期せぬ無限ループが発生するので注意が必要です。

useRef

記述の仕方

import { useRef } from 'react'

const Hooks = () => {
    const inputRef = useRef(null)

    const handleClick = () => {
      console.log(ref.current)
    }

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={handleClick}>クリック</button>    
    </div>
  )
}

export default Hooks

説明

useRefはReferenceが参照するという意味を持つように、値を参照することができるフックです。引数には任意の初期値を設定します。

useRefは返り値にcurrentというプロパティをもつオブジェクトを返します。currentプロパティには初期値が設定されるため、宣言した変数にcurrentプロパティからアクセスすることで初期値を取得することができます。
また、この初期値は書き換え可能で、値を保持することができます。

ここで、思うことが

「値を保持できるならuseStateと何が違うの?」

ということです。これには明確な答えがあり、それは値の変更時に再レンダリングが起きないということです。useStateは保持している値が変更される(状態が変化する)たびにレンダリングが起きますが、useRefではレンダリングが起きません。ここに使い方の明確な違いがあります。

そのため、以下のようなコードではカウントがうまく機能しません。

import { useRef } from 'react'

const Hooks = () => {
    const count = useRef(0)

    const handleClick = () => {
      count.current = count.current + 1
      console.log(count.current)
    }

  return (
    <div>
        <button onClick={handleClick}>カウント</button>
        <div>{count.current}</div>       
    </div>
  )
}

export default Hooks

一見、handleClick関数によってcountに保持される値が1ずつ増えているように思えますが、実際の画面ではカウントが増えていきません。ただし、コンソールにはcountのcurrentプロパティに保存される値は変化していくことが見られると思います。
このようにuseRefとuseStateの違いを明確に理解するとよりよい開発につながるかと思います。

useContext

記述の仕方

// 親コンポーネント

import { createContext } from 'react'
import Chiledhooks from './Childhooks'

export const HooksContext = createContext()

const text = 'コンテキストの使い方'

const Hooks = () => {

  return (
    <HooksContext.Provider value={text}>
      <div>
        <Chiledhooks />
      </div>
    </HooksContext.Provider>
  )
}

export default Hooks
// 子コンポーネント

import { useContext } from 'react'
import { HooksContext } from './Hooks'

const Childhooks = () => {
    const childText = useContext(HooksContext)

  return (
    <div>
      <p>{childText}</p>
    </div>
  )
}

export default Childhooks

説明

useContextは親コンポーネントから子コンポーネントにデータを受け渡すことができるフックです。親コンポーネントから子コンポーネントにデータを受け渡すときはPropsを用いるのが基本ですが、階層が深くなったり、階層の先で枝分かれしていたりするとPropsを渡し続けてバケツリレーのように立って記述が冗長になってしまいます。

そこで便利なのがuseContextです。親コンポーネントでコンテキストを用意すると、親コンポーネントの配下にある階層のどの子コンポーネントでもそれを参照することができるようになります。

まず、コンテキストを用意します。
createContext()でコンテキストを定義します。上記の例では、HooksContextを変数名として定義しました。これでコンテキストを引き渡す準備ができました。
実際にコンテキストを引き渡すのは、Providerプロパティです。
引き渡したい子コンポーネントをこのProviderコンポーネントでラップします。この際、引き渡したい値をvalue 属性に設定します。
これで子コンポーネントに値をひきわたすことができました。

続いて子コンポーネントでコンテキストを参照します。
これはとても簡単で、useContextで参照することができます。引数には、参照したい値を持っているコンテキストを入れます。するとそこに格納されているコンテキストを取得することができます。

カスタムフック

記述例

// カスタムフックを作成

import { useState } from 'react'

export default function useCount() {
    const [count, setCount] = useState(0)

    const countUp = () => {
        setCount(count + 1)
    }

    const countDown =() => {
        setCount(count - 1)
    }

    return [count, countUp, countDown]
}
import useCount from './useCount'

const Hooks = () => {
  const [count, countUp, countDown] = useCount()

  return (
    <div>
      <p>{count}</p>
      <button onClick={countUp}>+</button>
      <button onClick={countDown}>ー</button>
    </div> 
  )
}

export default Hooks

説明

カスタムフックとはその名の通り自作したフックのことです。難しそうに聞こえますが、「関数コンポーネントから呼び出すことができる関数」というだけです。開発規模が大きくなればなるほど、再利用したいコードが増えていきます。そこで、そのようなコードを関数として1か所にまとめておくことができるものがカスタムフックです。

カスタムを作成する際には

  1. 関数名をuseOoooとする

  2. 関数内で別の’フックを使用する

  3. コンポーネントで再利用したいコードを戻り値として設定する

以上のことを満たしていることが条件になるので注意が必要です。

用意したカスタムフックを別のコンポーネントで利用するときは、既存のフックと同じように、まずはimportでカスタムフックを呼びます。
そしたら、stateとハンドラを変数を配列として用意して受け取るだけです。

まとめ

今回は、基本的なフックの紹介と簡単な説明をまとめてみました。リアクトにはもっと便利なフックが多く用意されています。これらをうまく利用することでより簡潔なコードを書くことができるでしょう。
また別の記事で別のフックもまとめたいと思います。

最後までご愛読ありがとうございました。


いいなと思ったら応援しよう!