7-4. Hooks - useReducer

송한솔·2023년 4월 27일
0

ReactStudy

목록 보기
34/54

useReducer란?

useReducer는 useState보다 더 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트해 주고 싶을 때 사용하는 Hook입니다.

리듀서는 현재 상태, 그리고 업데이트를 위해 필요한 정보를 담은 액션(action)값을 전달받아 새로운 상태를 반환하는 함수입니다.
리듀서 함수에서 새로운 상태를 만들 때는 반드시 불변성을 지켜주어야 합니다.

function reducer(state,action){
	return {...}; // 불변성을 지키면서 업데이트한 새로운 상태를 반환합니다.
}

액션 값은 주로 다음과 같은 형태로 이루어져 있습니다,

{
	type: 'INCREMENT',
}

후에 다뤄볼 리덕스에서 액션 객체에는 어떤 액션인지 알려주는 type 필드가 꼭 있어야 하지만 useReducer에서 사용하는 액션 객체는 반드시 type을 지니고 있을 필요가 없습니다.


useReducer 사용해보기

useReducer를 사용하여 기존의 Counter 컴포넌트를 다시 구현해보세요.

Counter.js`

import { useReducer } from 'react';

function 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 = () => {
    // state의 기본값
    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;

state는 현재 가리키고 있는 상태, dispatch는 액션을 발생시키는 함수입니다.

dispatch(action)과 같은 형태로, 함수 안에 파라미터로 액션 값을 넣어 주면 리듀서 함수가 호출되는 구조입니다.

useReducer를 사용했을 때의 가장 큰 장점은 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있다는 것입니다.

컴포넌트 바깥으로 빼낼 수 있다는 장점?

보는 바와 같이 Counter 컴포넌트 바깥으로 reducer를 빼서 state를 관리할 수 있습니다.


input상태 관리하기

useReducer를 사용하여 Info 컴포넌트에서 인풋상태를 관리해 보겠습니다.

기존에는 인풋이 여러 개여서 useState를 여러 번 사용했습니다.
useReducer를 사용하면 기존에 클래스형 컴포넌트에서 input 태그에 name값을 할당하고 e.target.name을 참조하여 setState를 해준 것과 유사한 방식으로 작업을 처리할 수 있습니다

Info.js컴포넌트를 수정해 봅시다.

// Info.js
import { useReducer } from 'react';

function 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);
        console.log(e.target);
    };

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

export default Info;

제가 이해한 바에 따르면

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

…state,로 기존의 name, nickname을 받아오고

받아온 state를 [action.name]란 이름으로 추적하여 action.value를 할당합니다.

즉, 받아온 state에서 추적할[action.name]목록을 할당받고,

할당받은 action.name의 action.value값을 추적하여 state를 업데이트합니다.

0개의 댓글