何番煎じだって話ですが、タイトルの通りです。
公式サイトにも使い方はありますが、
表現が自分の中でよく飲み込めないので自分用にサンプルとわかりにくいところだけ書き起こしてみました。
useState
ここに関しては公式を読めば特に補足はいらないかなと思います。
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で画面に表示されます。
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はレンダリング後に実行される
上記例では特に問題になりませんが下記のようにするとエラーが発生します。
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を実装し、 UsingSharedState1
とUsingSharedState2
でuseContextを宣言し、その値を参照及び変更できるようにした例です。
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>
)
}
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;
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;
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
コンポーネントがレンダリングされる度にオブジェクトの再生成を防ぐためのもの
という認識(間違ってるかも)
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も書き残しておこうと思います。