usecallback , usememo , useref , usereducer hook


この記事では、usecallback、usememo、useref、usereducer hookの使い方について説明します。


usecallback hook :コールバック関数を記憶します.したがって、その関数の新しいインスタンスは作成されません.そして、依存値が変更されるとき、それはそれを忘れるだけです.
import React, { useCallback, useState } from "react";
import "./App.css";
import Title from "./components/Title/Title";

function App() {
 const [increase1, setIncrease1] = useState(0);
 const [increase5, setIncrease5] = useState(0);

 const handleIncrease1 = useCallback(() => {
   console.log("inside 1");
   setIncrease1(increase1 + 1);
 }, [increase1]);

 const handleIncrease5 = useCallback(() => {
   console.log("inside 5");
   setIncrease5(increase5 + 5);
 }, [increase5]);

 return (
   <div className="App">
     <Title />
     {/* increase value by 1 */}
     <h4>Increase value by 1</h4>
     <p>{increase1}</p>
     <button onClick={handleIncrease1}> Increase by 1</button>

     {/* increase value by 5 */}
     <h4>Increase value by 5</h4>
     <p>{increase5}</p>
     <button onClick={handleIncrease5}> Increase by 5</button>
   </div>
 );
}

export default App;
USEMEMOフック:usecallbackフックとは少し異なります.UseCallbackは関数全体を暗記しますが、関数の戻り値のみを暗記します.そして、依存値が変更されるとき、それは忘れます.
import React, { useCallback, useMemo, useState } from "react";
import "./App.css";
import Title from "./components/Title/Title";

function App() {
 const [increase1, setIncrease1] = useState(0);
 const [increase5, setIncrease5] = useState(0);

 const handleIncrease1 = useCallback(() => {
   console.log("inside 1");
   setIncrease1(increase1 + 1);
 }, [increase1]);

 const handleIncrease5 = useCallback(() => {
   console.log("inside 5");
   setIncrease5(increase5 + 5);
 }, [increase5]);

 const isEvenOrOdd = useMemo(() => {
   let i = 0;
   while (i < 1000000000) i++;
   return increase1 % 2 === 0;
 }, [increase1]);

 return (
   <div className="App">
     <Title />
     {/* increase value by 1 */}
     <h4>Increase value by 1</h4>
     <p>{increase1}</p>
     <p>{isEvenOrOdd ? "Even" : "Odd"}</p>
     <button onClick={handleIncrease1}> Increase by 1</button>

     {/* increase value by 5 */}
     <h4>Increase value by 5</h4>
     <p>{increase5}</p>
     <button onClick={handleIncrease5}> Increase by 5</button>
   </div>
 );
}

export default App;
useref :要素またはその値を取得したい場合は、ドキュメントを使用します.GetElementByIdまたはドキュメント.getElementsByClassNameなどを使用すると、反応でそれらを使用できますが、それは良い実行ではありません.この反応を解決するために私達にuserefフックを与える.参照するノード要素を指定する必要があります.参照される変数の参照先ノードを返します.カレント
import React, { useEffect, useRef } from "react";

const Form = () => {
  const inputRef = useRef();

  useEffect(() => {
    console.log(inputRef.current.value);
  }, []);
  return (
    <div>
      <input ref={inputRef} />
    </div>
  );
};

export default Form;

If you have to use ref to a child component then you have to use forward ref to pass ref from parent to child component


REFが位置する親コンポーネント
import React, { useEffect, useRef } from "react";
import "./App.css";
import Input from "./components/Input";

function App() {
 const inputRef = useRef();

 useEffect(() => {
   inputRef.current.focus();
 });
 return (
   <div className="App">
     <Input placeholder="Enter your name" ref={inputRef} type="text" />
   </div>
 );
}

export default App;
refを使用したい子コンポーネント
import React from "react";

const Input = ({ type, placeholder }, ref) => {
 return <input ref={ref} type={type} placeholder={placeholder} />;
};

const forwardedInput = React.forwardRef(Input);

export default forwardedInput;

Here’s a little trick of using useRef. When you want to use a function which is scoped inside the useEffect hook.


import React, { useEffect, useRef, useState } from "react";

const Clock = () => {
 const [date, setDate] = useState(new Date());
 const intervalRef = useRef();

 const tick = () => {
   setDate(new Date());
 };

 useEffect(() => {
   intervalRef.current = setInterval(tick, 1000);

   // do the cleanup stop the timer
   return () => {
     clearInterval(intervalRef.current);
   };
 }, []);
 return (
   <div>
     <p>Time: {date.toLocaleTimeString()}</p>
     <p>
       <button onClick={() => clearInterval(intervalRef.current)}>Stop</button>
     </p>
   </div>
 );
};

export default Clock;
usereducer : usereducerは配列のようです.プロトタイプ.バニラJSにおける低減法違いは、還元法が還元関数と初期値を取るということです、しかし、usereducerは第2のパラメタとして還元関数と初期状態を取ります.reduceメソッドは単一の値を返すが、usereducerはタプル[ newstate , dispatch ]を返す
import React, { useReducer } from "react";
import "./App.css";

const initialState = 0;
const reducer = (state, action) => {
 switch (action) {
   case "increment":
     return state + 1;
   case "decrement":
     return state - 1;
   default:
     return state;
 }
};
function App() {
 const [count, dispatch] = useReducer(reducer, initialState);
 return (
   <div className="App">
     <p>{count}</p>
     <button onClick={() => dispatch("increment")}>Increase</button>
     <button onClick={() => dispatch("decrement")}>Decrease</button>
   </div>
 );
}

export default App;

You can use useReducer in a complex situation where you have different as for example counters and they have a different functions to update their value.


import React, { useReducer } from "react";

const initialState = {
 counter: 0,
 counter2: 0,
};
const reducer = (state, action) => {
 /* you have to merge object immutably to do that use the spread operator */
 switch (action.type) {
   case "increment":
     return { ...state, counter: state.counter + action.value };
   case "decrement":
     return { ...state, counter: state.counter - action.value };
   case "increment2":
     return { ...state, counter2: state.counter2 + action.value };
   case "decrement2":
     return { ...state, counter2: state.counter2 - action.value };
   default:
     return state;
 }
};

/* you have to merge state immutably */
function Counter() {
 const [count, dispatch] = useReducer(reducer, initialState);
 return (
   <React.Fragment>
     {/* counter 1 */}
     <div>
       <p>Counter1: {count.counter}</p>
       <button
         onClick={() =>
           dispatch({
             type: "increment",
             value: 1,
           })
         }
       >
         Increment by 1
       </button>

       <button
         onClick={() =>
           dispatch({
             type: "decrement",
             value: 1,
           })
         }
       >
         Decrement by 1
       </button>
     </div>

     {/* counter 2 */}
     <div>
       <p>Counter2: {count.counter2}</p>
       <button
         onClick={() =>
           dispatch({
             type: "increment2",
             value: 1,
           })
         }
       >
         Increment2 by 1
       </button>

       <button
         onClick={() =>
           dispatch({
             type: "decrement2",
             value: 1,
           })
         }
       >
         Decrement2 by 1
       </button>
     </div>
   </React.Fragment>
 );
}

export default Counter;