Hooks

57304 ワード

Hooksは、レスポンス16.8のバージョンで導入された機能で、ユーザーステータス管理機能とレンダリング後のタスクのユーザー効果を設定し、関数構成部品では以前はできなかったさまざまなタスクを実行できます.
実験を行うための新しいプロジェクトを作成します.
useState
useStateは最も基本的なHooksであり、関数要素を可変状態にすることができます.
useStateを使用してデジタルカウンタ機能を実現しましょう.
Counter.js
import React, { useState } from "react";

const Counter = () => {
  const [value, setValue] = useState(0);

  return (
    <div>
      <p>
        현재 카운터 값은 <b>{value}</b>입니다.
      </p>
      <button onClick={() => setValue(value + 1)}> +1 </button>
      <button onClick={() => setValue(value - 1)}> -1 </button>
    </div>
  );
};

export default Counter;

複数使用useState
useStateは1つのステータス値しか受け入れられません.構成部品に管理が必要な状態が複数ある場合は、usStateを複数回使用できます.
テストのためにinfoコンポーネントを作成します.
Info.js
import React, { useState } from "react";

const Info = () => {
  const [name, setName] = useState("");
  const [nickname, setNickname] = useState("");

  const onChangeName = (e) => {
    setName(e.target.value);
  };

  const onChangeNickname = (e) => {
    setNickname(e.target.value);
  };
  return (
    <div>
      <div>
        <input value={name} onChange={onChangeName}></input>
        <input value={nickname} onChange={onChangeNickname}></input>
      </div>
      <div>
        <div>
          <b>이름: {name}</b>
        </div>
        <div>
          <b>닉네임: {nickname}</b>
        </div>
      </div>
    </div>
  );
};

export default Info;

useEffect
userEffectはHookで、反応素子をレンダリングするたびに特定の操作を設定できます.クラス構成部品の構成部品DidMountと構成部品DidUpdateを組み合わせることができます.
既存のinfoコンポーネントにuserEffectを適用してみましょう.
Info.js - useEffect
import React, { useEffect, useState } from "react";
...
const [nickname, setNickname] = useState("");
...
  useEffect(() => {
    console.log("렌더링 끝!");
    console.log({
      name,
      nickname,
    });
  });
return (...

マウント時にのみ実行したい場合
デバイスが画面上でレンダリングされたときにuserEffectで設定された関数だけを実行し、更新時に実行したくない場合は、関数の2番目のパラメータを空の配列に入れるだけです.
Info.js - useEffect
...
  const [nickname, setNickname] = useState("");
  useEffect(() => {
    console.log("마운트될 때만 실행됩니다.");
  }, []);
return(...

特定の値の更新時にのみ実行します.
useEffectを使用して値が変更されたときにのみ実行する場合は、次のようにクラス構成部品が作成されます.
componentDidUpdate(prevProps, prevState) {
  if(prevProps.value !== prevState.value) {
    doSomething();
特定の操作はpropsの値が変化した場合にのみ実行されます.
このタスクをuserEffectの2番目のパラメータに渡す配列に配置し、チェックしたい値を配列に挿入します.
InfoコンポーネントのuseEffect部分を変更します.
Info.js - useEffect
...
  const [nickname, setNickname] = useState("");
  useEffect(() => {
    console.log(name);
  }, [name]);
return(...

クリーンアップ
デフォルトでは、userEffectはレンダリング後すぐに実行されます.その実行条件は、2番目のパラメータに何を配置するかによって異なります.
構成部品のアンインストール前または更新前にアクションを実行する場合は、userEffectでクリーンアップ関数を返す必要があります.
Info.js - useEffect
...
  const [nickname, setNickname] = useState("");
  useEffect(() => {
    console.log("effect");
    console.log(name);
    return () => {
      console.log("cleanup");
      console.log(name);
    };
  }, [name]);
return(...

AppコンポーネントにInfoコンポーネントの可視性を変更させます.今回もUSStateを使ってステータスを管理しています.
App.js
import Info from "./Info";
import { useState } from "react";

const App = () => {
  const [visible, setVisible] = useState(false);
  return (
    <div>
      <button onClick={() => setVisible(!visible)}>
        {visible ? "숨기기" : "보이기"}
      </button>
      <hr></hr>
      {visible && <Info></Info>}
    </div>
  );
};

export default App;
コンポーネントが表示されると、コンソールに効果が表示され、消えるとcleanupが表示されます.

レンダーするたびに、呼び出し後の整理関数が表示されます.呼び出し後に関数を整理すると、更新前の値が表示されます.
アンインストール時にクリーンアップ関数のみを呼び出す場合は、userEffect関数の2番目のパラメータに空の配列を配置します.
Info.js - useEffect
  useEffect(() => {
    console.log("effect");
    return () => {
      console.log("unmount");
    };
  }, []);
useReducer
useReducerは、素子によって異なる状態を異なる値に更新するためのHookです.(2)reducerの概念を理解するには,まずreduceを理解する.ここでの内容が難しい場合は、(1)なぜReduxを使うのか。(2)Reduserとは?を見て行うのが望ましい.
リダイレクトは、現在のステータスと更新に必要な情報を含むアクション値を受信し、新しいステータスを返す関数です.reducer関数で新しいステータスを作成する場合は、不変性を維持する必要があります.
function reducer(state, action) {
  return { ... } // 불변성을 지키면서 업데이트한 새로운 상태를 반환합니다.
アクション値は主に次のとおりです.
{
  type: 'INCREMENT',
  // 다른 값들이 필요하다면 추가로 들어감
}
リスナーで使用するアクションオブジェクトには、アクションがどのようなアクションであるかを示すtypeフィールドが必要ですが、ユーザがリスナーで使用するアクションオブジェクトにはtypeを持つ必要はありません.オブジェクトではなく文字列や数値であってもよい.
インプリメンテーションカウンタ
Counter.js
import React, { useReducer } from "react";

const INCREMENT = "INCREMENT";
const DECREMENT = "DECREMENT";

const reducer = (state, action) => {
  // action.type에 따라 다른 작업 수행
  switch (action.type) {
    case INCREMENT:
      return { value: state.value + 1 };
    case DECREMENT:
      return { value: state.value - 1 };
    default:
      // 아무것도 하지 않을 때 기존 상태 반환
      return state;
  }
};

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { value: 0 });

  return (
    <div>
      <p>
        현재 카운터 값은 <b>{state.value}</b>입니다.
      </p>
      <button onClick={() => dispatch({ type: INCREMENT })}> +1 </button>
      <button onClick={() => dispatch({ type: DECREMENT })}> -1 </button>
    </div>
  );
};

export default Counter;
userreducerの最初のパラメータにはreducer関数が含まれ、2番目のパラメータにはreducerのデフォルト値が含まれます.このHOOKを使用してstate値とdispath関数を受信します.stateは現在指す状態であり,dispathは励起動作の関数である.動作値をパラメータとして関数に入れることでコールバック関数を呼び出す構造であって、dispath(action)と同じ形式である.
userReducerを使用する最大の利点は、素子更新ロジックを素子から削除できることである.
入力ステータスの管理
ここでは、Use Reducerを使用してinfo構成部品の入力状態を管理します.入力方式がたくさんあるのでusStateを何度も使いましたusereducerを使用すると、既存のクラス構成部品がinputラベルにname値を割り当て、e.targetします.タスクは、nameを参照してStateを設定するのと同様に処理できます.
Info.js
import React, { useReducer } from "react";

const reducer = (state, action) => {
  return {
    ...state,
    [action.name]: action.value,
  };
};

const Info = () => {
  const [state, dispatch] = useReducer(reducer, {
    name: "",
    nickname: "",
  });

  const { name, nickname } = state;

  const onChange = (e) => {
    dispatch(e.target);
  };

  return (
    <div>
      <div>
        <input name="name" value={name} onChange={onChange}></input>
        <input name="nickname" value={nickname} onChange={onChange}></input>
      </div>
      <div>
        <div>
          <b>이름: {name}</b>
        </div>
        <div>
          <b>닉네임: {nickname}</b>
        </div>
      </div>
    </div>
  );
};

export default Info;
useReducerの動作は任意の値であってもよい.今回は,イベントオブジェクトのe.target値自体を動作値として用いる.このように入力を管理することで、入力の数にかかわらず、コードの簡潔性を維持することができます.
useMemo
userMemoを使用すると、関数要素内部の演算を最適化できます.
まず、リストに数値を追加した後、追加した数値の平均値を示す関数コンポーネントを作成します.
Average.js
import React, { useState } from "react";

const getAverage = (numbers) => {
  console.log("평균값 계산중..");
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState("");

  const onChange = (e) => {
    setNumber(e.target.value);
  };

  const onInsert = (e) => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  };

  return (
    <div>
      <input
        value={number}
        onChange={onChange}
        onKeyPress={(e) => {
          if (e.key === "Enter") onInsert();
        }}
      ></input>
      <button onClick={onInsert}>등록</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <div>
        <b>평균값: {getAverage(list)}</b>
      </div>
    </div>
  );
};

export default Average;
ただし、数値の登録時でも、入力内容の変更時でも、作成したgetaverage関数が呼び出されていることがわかります.このようにレンダリングするたびに計算は無駄でしょう.
useMemo Hookを使用すると、これらの操作を最小限に抑えることができます.演算は、レンダリング中に値が変更された場合にのみ実行されます.必要な値が変更されていない場合は、以前に計算した結果を使用できます.
コードを修正しましょう.
Average.js
...
+  const avg = useMemo(()=> getAverage(list), [list]);
return(
  ...
  <b>평균값: {avg}</b> // {getAverage(list)} -> {avg}
  ...)
useCallback
useCallbackはuseMemoによく似た関数です.主にレンダリングのパフォーマンスを最適化する必要がある場合に使用します.このHookでは、作成した関数を再使用できます.
AverageコンポーネントにonChangeとonInsert関数が宣言されていますよね?この宣言では、構成部品を再レンダリングするたびに新しく作成した関数が使用されます.
useCallbackを使用して最適化します.
Average.js