応答技術:Hooks[useReducer,useMemo,useCallback]


useReducer


useReducerは、素子によって異なる状態を異なる値に更新するためのHookです.
Reducerは、現在のステータスと更新に必要な情報を含むアクション値を受信し、新しいステータスを返す関数です.reducer関数で新しいステータスを作成する場合は、不変性を維持する必要があります.
function reducer(state,action){
  return { ... }; //불변성을 지키면서 업데이트한 새로운 상태를 반환
         }
動作値は主に以下の形式で構成されます.
{
  type:"INCREMENT"
  //다른 값들이 필요하다면 추가로 들어감
}
usereducerで使用する動作オブジェクトにtypeがあるとは限らない.オブジェクトではなく文字列や数字でも関係ありません.

usereducerを使用してカウンタを実装する

function reducer(state,action){
    switch(action.type){
        case 'INCREMENT':
            return { value: state.value + 1};
        case 'DECREMENT':
            return { value: state.value - 1};
        default:

        return state;
    }
}

const useReducer = () => {
    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 useReducer;
usereducerの最初のパラメータにはreducer関数が含まれ、2番目のパラメータには対応するreducerのデフォルト値が含まれます.このHookを使用してstate値とdispatch関数を受信します.ここでstateは現在指す状態であり、dispatchは動作をトリガする関数である.dispatch(action)と同じ形式で、関数にパラメータの形式で動作値を入力するとreducer関数を呼び出すことができます.usereducerを使用する最大の利点は、素子更新ロジックを素子から除外できることです.

userReducerを使用して入力ステータスを管理する


前回作成したInfoには複数の入力があるので、usStateを複数回使用します.usereducerを使用すると、既存のクラス構成部品はinputラベルにname値、e.targetを指定します.タスクは、参照nameと同様にsetStateとして処理できます.
import React, { useReducer } from 'react';

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

const ReducerInfo = () => {
    const [state,dispatch] = useReducer(reducer,{
        name:'',
        nickname: '',
        phone: ''
    })
    const {name, nickname,phone,address,email} = state;
    const onChange = e => {
        dispatch(e.target);
    }
    return (
        <div>
        <form action="">
          <input name="name" value={name} onChange={onChange} type="text" />
          <input name="nickname" value={nickname} onChange={onChange} type="text" />
          <input name="phone" value={phone} onChange={onChange} type="number" />
          <input name="address" value={address} onChange={onChange} type="address" />
          <input name="email" value={email} onChange={onChange} type="email" />
        </form>
            <div>
                <b>이름</b>: {name}
                <b>닉네임</b>: {nickname}
                <b>핸드폰번호</b>: {phone}
                <b>주소</b>: {address}
                <b>이메일</b>: {email}
            </div>
        </div>
    );
};

export default ReducerInfo;
usereducerのアクションでは、任意の値を使用できます.したがって、イベントオブジェクトが持つe.target値自体をactionの値として使用します.このように入力法を管理することで,入力法の数が増えてもコードの簡潔性を保つことができる.

useMemo


useMemoを使用すると、関数要素の内部で発生する演算を最適化できます.まず、リストに数値を追加し、追加した数値の平均値を表示する関数コンポーネントを作成します.
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}/>
            <button onClick={onInsert}>등록</button>
            <ul>
                {list.map((value,index) =>(<li key={index}>{value}</li>))}
            </ul>
            <div>
                <b>평균값:</b>{getAverage(list)}
            </div>
        </div>
    );
};

export default Average;
上記のコードに従って作成すると、コンソールウィンドウに表示され、数値を入力するたびにgetaverage関数が呼び出されます.入力内容の変更時に平均値を再計算する必要がないため、useMemoを使用して操作を最適化できます.
useMemoは、レンダリング中に特定の値が変更された場合にのみ演算を実行し、必要な値が変更されていない場合は、以前に計算した結果を再使用する方法です.
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('');
    }
    const avg = useMemo(() => getAverage(list), [list]);
    return (
        <div>
            <input value={number} onChange={onChange}/>
            <button onClick={onInsert}>등록</button>
            <ul>
                {list.map((value,index) =>(<li key={index}>{value}</li>))}
            </ul>
            <div>
                <b>평균값:</b>{avg}
            </div>
        </div>
    );
};

export default Average;

useCallback


useCallbackはuseMemoとかなり似た関数です.主にレンダリングのパフォーマンスを最適化する必要がある場合に使用します.このHookを使用すると、作成した関数を再使用できます.
実装したばかりのAverage構成部品では、onChangeとonInsert関数が宣言されています.これにより、構成部品を再レンダリングするたびに、新しく作成した関数が使用されます.ほとんどの場合、この方法は問題ありませんが、エレメントのレンダリングが頻繁に発生したり、レンダリングが必要なエレメントの数が増えたりする場合は、この点を最適化することが望ましいです.
const Average = () => {
    const [list,setList] = useState([]);
    const [number,setNumber] = useState('');
  
    //onChange함수는 컴포넌트가 처음 랜더링 될 때만 함수를 생성하고 이후는 재활용
    const onChange = useCallback(e => {
        setNumber(e.target.value);
    },[])
    
    //onInsert 함수는 number 또는 list가 바뀔때만 함수 생성
    const onInsert = useCallback(e =>{
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    },[number,list])
    
    const avg = useMemo(() => getAverage(list),[list])
    return (
        <div>
            <input value={number} onChange={onChange}/>
            <button onClick={onInsert}>등록</button>
            <ul>
                {list.map((value,index) =>(<li key={index}>{value}</li>))}
            </ul>
            <div>
                <b>평균값:</b>{avg}
            </div>
        </div>
    );
};

export default Average;
useCallbackの最初のパラメータに作成したい関数を追加し、2番目のパラメータに配列を追加すればよい.(useEffect、useMemoと同様)この配列は、値を変更するときに関数を再作成する必要があることを示す必要があります.
onChangeのように空の配列を入れると、要素をレンダリングするときに作成された関数が繰り返し使用されます.onInsertのように配列に特定の値が含まれている場合は、コンテンツが変更されるたびに新しく作成された関数が使用されます.
関数内部でステータス値に依存する必要がある場合は、2番目のパラメータに含める必要があります.