LoginSignup
1

More than 3 years have passed since last update.

React フック API の使い方メモ

Last updated at Posted at 2020-08-22

何番煎じだって話ですが、タイトルの通りです。

公式サイトにも使い方はありますが、
表現が自分の中でよく飲み込めないので自分用にサンプルとわかりにくいところだけ書き起こしてみました。

useState

ここに関しては公式を読めば特に補足はいらないかなと思います。

UseStateSample.jsx

import React, { useState } from 'react'

const UseStateSample = () => {
  const [count, setCount] = useState(0)
  return (
    <>
      <h2>Use State Sample</h2>
      Count: {count}
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  )
}

export default UseStateSample;

useEffect

基本機能はレンダリングが行われるタイミングでここの処理を実行します。下記例ではcountの初期値を0に設定していますが、useEffect内で+1されているので1で画面に表示されます。

UseStateSample.jsx
import React, { useState, useEffect } from 'react'

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

  useEffect(() => {
    setCount((count) => count + 1)
  }, []);

  return (
    <>
      Count: {count}      
    </>
  )
}

export default UseEffectSample;

重要なポイントとしては以下3点かなと。

セッタ(上記例でいうところのsetCount)はその時点での値を引数として受け取る

setCount((count) => count + 1)

上記のcountのことです。
例ではuseStateで0を入れているので初回は0が入ってきます。

第2引数に依存する値を配列で指定できる`

これも実は上記例ですでに使用している機能です。
上記例は下記のように空配列を指定してあげないと、無限にレンダリングが起こります。

  useEffect(() => {
    setCount((count) => count + 1)
  }, []);

useEffectでは第2引数に指定がないとprops(上述ではない)かstateが更新されるたびに実行されることになるからです。
countを更新した際に再レンダリングされないようにするために空配列を指定しています。
空配列が指定されるとuseEffectはマウント時とアンマウント時にしか実行されません。

useEffectはレンダリング後に実行される

上記例では特に問題になりませんが下記のようにするとエラーが発生します。

UseStateSample.jsx
import React, { useState, useEffect } from 'react'

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

  useEffect(() => {
    setCount({ value: 1 })
  }, []);

  return (
    <>
      Count: {count.value}      
    </>
  )
}

export default UseEffectSample;

UseEffectSample.jsx:12 Uncaught TypeError: Cannot read property 'value' of undefined
valueなんて値はないよって言ってます。これはuseEffectが実行される前にレンダリングされてcount.valueにアクセスされていることを意味します。

useContext

私の現在の理解では複数のコンポーネント間で共有できるオブジェクトを提供するもの です。
わかりやすいところでいくと一番最初に挙げたStateを複数コンポーネント間で共有することができるようになります。
ちょっとアレンジした例を紹介。
以下ではcreateContextでuseContextを実装し、 UsingSharedState1UsingSharedState2でuseContextを宣言し、その値を参照及び変更できるようにした例です。

index.jsx
import UseContextSample from  '../components/UseContextSample'
import UsingSharedState1 from  '../components/UsingSharedState1'
import UsingSharedState2 from  '../components/UsingSharedState2'
import styles from '../styles/Home.module.css'
export default function Home() {
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <UseContextSample>
          <UsingSharedState1/>
          <UsingSharedState2/>
        </UseContextSample>
      </main>
    </div>
  )
}

UseContextSample.jsx
import React, { useState } from 'react'

export const UseContext = React.createContext({
  value: 0,
  changeValue: () => {}
});

const UseContextSample = ({ children }) => {
  const [count, setCount] = useState(0)

  return (
    <UseContext.Provider value={{value: count, changeValue: (count) => setCount(count)}}>
      {children}
    </UseContext.Provider>
  )
}

export default UseContextSample;
UsingSharedState1.jsx
import React, { useContext } from 'react'
import { UseContext } from './UseContextSample'

const UsingSharedState1 = () => {
  const sharedData = useContext(UseContext);
  return (
    <>
      <span>UsingSharedState1: {sharedData.value}</span>
      <button onClick={() => sharedData.changeValue(1)}>UsingSharedState1 Button</button>
    </>
  )
}

export default UsingSharedState1;
UsingSharedState2.jsx
import React, { useContext } from 'react'
import { UseContext } from './UseContextSample'

const UseContextSample2 = ({ children }) => {
  const sharedData = useContext(UseContext);
  return (
    <>
      <span>UsingSharedState2: {sharedData.value}</span>
      <button onClick={() => sharedData.changeValue(2)}>UsingSharedState2 Button</button>
    </>
    )
}

export default UseContextSample2;

useMemo

コンポーネントがレンダリングされる度にオブジェクトの再生成を防ぐためのもの
という認識(間違ってるかも)

UseMemoSample.jsx
import React, { useContext, useMemo } from 'react'
import { UseContext } from './UseContextSample'

const UseMemoSample = () => {
  const sharedData = useContext(UseContext);
  const array = [...Array(10000000).keys()]
  const memo = useMemo(() => {
    let temp = 0;
    array.map((index) =>{
      temp = temp + index;
    })
    return temp
  }, [xxx]);
  return (
    <>
      <p>{memo}</p>
    </>
  )
}

export default UseMemoSample;

無理やりな例ですが、上記の例でコンポーネントがレンダリングされるたびにmemoの値を計算するのは無駄に見えますよね。
これを毎回実行しないようにするためのもの。useEffectと同様に第2引数で依存変数を定義すると、実行されるタイミングを制御できます。

useCallback

useMemoの関数版。
関数の場合は実行されなくても、そのインスタンスをコンポーネントとともに生成してしまいます。
性能向上やメモリの節約(?)をするために、毎回生成する必要のないものについてはuseCallbackによって生成します。例によって、第2引数には依存変数を定義できます。

一旦は以上です。
時間があるときに他のHooksも書き残しておこうと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1