主なReactHooks

React

Reactで使用されるおもなHooksのまとめ

useState

値が変わるとレンダリングが実行される。

const [値, セット関数] = useState(初期値);

で設定。仮想DOMを監視して差分があれば差分だけをレンダリングする。差分だけをレンダリングするのでパフォーマンスがいい。

const [count, setCount] = useState(0);

  function handleClick(){
    setCount(count + 1);
  }

  return (
   <div>
    <h1>{count}</h1>
    <button onClick={handleClick}>add count</button>
   </div>
  )

useRef

useRefはその要素のいろいろな情報を参照できる。

const myRef = useRef();

  return (
   <div>
    <input type="text" ref={myRef} />
    <button onClick={handleRef}>button</button>
   </div>
  )

上記のmyRefをコンソールで見ると、input要素の様々な情報が取得されている。値、要素、幅、高さ、属性等。

myRef.current.valueで入力された値を見ることができる

  const myRef = useRef();

  const handleRef = () => {
    console.log(myRef.current.value);
  }

  return (
   <div>
    <input type="text" ref={myRef} />
    <button onClick={handleRef}>button</button>
   </div>
  )

タグに付けなくても、変数.currentで値を保持できる。ただ保持するだけで、レンダリングはしない


    const countValue = useRef(0);

    function handleClick(){
        countValue.current++;
        console.log(countValue.current);
    }

    return (
        <div>
            <button onClick={handleClick}>Click</button>
        </div>
    );

useEffect

コンポーネントのマウント時、第2引数の値変更時に実行される。

●第2引数の配列に何も入れなければコンポーネントマウント時、ロード、リロードしたら実行される

useEffect(()=> {
    console.log("ページがロードされました");
  }, [])

●第2引数の配列に値を入れる。その値が変更されると実行される

useEffect(()=> {
    console.log("countに1足されました");
  }, [count])

実行タイミング: レンダリングの後に非同期で実行されます。これは、React が画面に変更を描画した後に実行されるため、ユーザーが変更を目にするタイミングよりも遅れて動作します。主な用途: データの取得、イベントリスナーの設定、外部リソースの操作など、画面描画には直接影響を与えない処理に使用します。パフォーマンスの利点: 描画をブロックしないので、ユーザーにとってよりスムーズな体験を提供します。

無限ループの例

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

カウントされる→useEffectコールバック関数実行→カウントされる→コールバック関数実行…
となって無限にループします。

useLayoutEffect

実行タイミング: レンダリング後すぐに同期的に実行されます。ブラウザが描画を行う前に実行されるため、DOM の更新が完了する前に処理を行うことができます。主な用途: DOM のレイアウトやスタイルの測定、DOM 要素の寸法や位置に依存する操作(例えば、要素のサイズを測定してその結果に基づいてスタイルを適用する場合)に使用します。パフォーマンスの影響: useLayoutEffect は描画をブロックするため、長時間の処理を行うとブラウザの描画が遅れ、ユーザーに対してラグが発生する可能性があります。

useMemo

計算結果をブラウザにメモ化(キャッシュ) して、再レンダリング時に不要な再計算を避けるために使う React のフックです。これにより、計算が重い処理を効率化したり、特定の依存関係が変わったときだけ処理を再実行することができます。

const memoizedValue = useMemo(() => {
  // 計算結果を返す処理
  return heavyCalculation();
}, [dependency1, dependency2]); // 依存配列

第一引数: 計算したい関数。第二引数: 依存関係の配列。これが変わったときにだけ、関数が再実行されます。依存配列の中に入れた値(dependency1, dependency2)が変化しない限り、heavyCalculation() は再度実行されません。

useCallback

関数をメモ化し、無駄な関数の再生成を避ける。useMemoは計算を記憶するが、useCallbackは関数を記憶するので、イベントハンドラや、コールバック関数の再生成を避けることができる。

useContext

propsで渡すことなく、好きな場所で変数や関数を呼び出せる。

例 ①全体のmain.jsxでAppコンポーネントをまずwrapする

//渡したい値
const myInfo = {
  name: "tenp",
  hobby: "programming",
};

//渡したい値のcontextを作る
const myInfoContext = createContext(myInfo);

createRoot(document.getElementById('root')).render(
  <myInfoContext.Provider value={myInfo}>
    <StrictMode>
      <App />
    </StrictMode>
  </myInfoContext.Provider>
)

export default myInfoContext;

ポイント
①渡したい値のcontextを作る(createContext)
②コンポーネントを作ったcontextにProviderをつけてwrapする。

③Providerタグにvalue={}で渡したい値を渡す
④作ったcontextをエキスポートする

useContext、やることが多い。wrapしてvalueで渡してさらにエキスポート…。

別のコンポーネントで使うとき

import myInfoContext from './main';

function App() {

  const myInfoInApp = useContext(myInfoContext);

  return (
   <div>
    <h1>{myInfoInApp.name}</h1>
   </div>
  )
}

①作ったcontextをインポート
②useContextでcontextを変数に格納
③jsx内で使う

たくさんのコンポーネントをまたいで渡したい変数・関数があるときに便利。

useReducer

reducerという処理の仕組みをカスタムして、dispatchという通知でその処理の種類をコントロールできる。簡単に言うと、いろんな処理をスイッチのように切り替えて実行できるアルゴリズムを作れます。

原理としては、ある状態(初期情報)が記録されているstoreに、何らかのアクションにより変更された処理後の状態(処理後の情報)をdispach(通知)して、足すなりなんなり計算をしてくれるのがreducerらしい。

const reducer = (state, action) => {
  switch(action.type){
    case "increment":
      return state + 1;
    case "decrement":
      return state - 1;
    default: 
      return state;
  }
}

function App() {

  const [state, dispatch] = useReducer(reducer, 0);

  return (
   <div>
    <h1>{state}</h1>
    <button onClick={()=> dispatch({type: "increment"})}>足し算</button>
    <button onClick={()=> dispatch({type: "decrement"})}>引き算</button>
   </div>
  )
}

const [state, dispatch] = useReducer(reducer, 0);
const [状態, 処理切り替え用関数] = useReducer(処理や計算してくれる機構, 初期値);

dispatch関数でタイプを切り替えて、それに応じた処理をreducerがやってくれます。いろいろ選択肢があったり分岐がある処理に使うのでしょう。

Custom Hook

自分でカスタムしたHooks。

簡潔に言うとuseStateやuseEffectなどのReactHookを組み込み、値を配列にいれて返す関数、のようなものだと思います。(今のところの自分の理解)

例①:値とオブジェクトを返す

import { useState } from "react";

function CustomHook(initialValue) {
  const [value, setValue] = useState(initialValue);
  const bind = {
    value: value,
    onChange: (e)=>setValue(e.target.value)
  };
  return [value, bind];
 
};
export default CustomHook;

valueとbindというオブジェクトを配列にいれて返しています

import CustomHook from './customhook';

function App() {

  const [fName, fbind] = CustomHook("");
  const [lName, lbind] = CustomHook("");

  return (
   <div>
    <form onSubmit={handleSubmit}>
      <label>FirstName
        <input type="text" {...fbind}/>
      </label>
      <label>LastName
        <input type="text" {...lbind}/>
      </label>
      <button type="submit">送信</button>
    </form>
   </div>
  )
}

作ったCustomHookをインポートし、分割代入で値を取り出して使っているだけです。よく見るのがこの形ってだけで、多分返す型や形は自由だと思います。…つまりカスタムフックってレンダリングを伴う関数ってだけな気がしてきました…。(再利用性と副作用処理、状態管理とかいろいろあるとは思いますが)

例②値と関数を返す

import { useState } from "react";

function CustomHook(initialValue) {
  const [count, setCount] = useState(initialValue);

    const increment = () => {
        setCount((prev) => prev + 1)
    }
    const decrement = () => {
        setCount((prev) => prev - 1)
    }
    const reset = () => {
        setCount(0);
    }

    return [count, increment, decrement, reset];
 
};
export default CustomHook;

このように足し算、引き算、リセットの関数を作り配列に入れて返します。

const [count, increment, decrement, reset] = CustomHook(0);

    return (
        <div>
            <button onClick={increment}>+</button>
            {count}
            <button onClick={decrement}>-</button>
            <button onClick={reset}>reset</button>
        </div>
    );

いろいろな計算ができる関数をそれぞれボタンに使えるようになります。