[React] useReducer 사용

November·2025년 1월 6일
post-thumbnail

useReducer

상태관리 로직이 복잡할 때 useState 대체품으로 사용
현재 상태액션을 받아 새로운 상태를 반환하는 리듀서(reducer) 함수를 통해 상태를 관리
useReducer리듀스 함수초기 상태를 인자로 받아 상태값과 디스패치 함수를 반환

  • 액션 : 상태를 변경하기 위한 정보가 담긴 객체로, 일반적으로 type 프로퍼티를 가지고 있으며, 필요에 따라 데이터를 포함할 수 있음
  • 디스패치 함수: 액션을 리듀서로 전달해서 상태를 업데이트 하는 함수

WHEN?

  • 상태 로직이 복잡하거나, 여러 하위 값으로 구성되 상태를 관리해야 할 때
  • 상태 업데이트 로직이 여러 종류의 액션에 의해 다르게 동작해야 할 때
  • 상태와 그 업데이트 로직을 컴포넌트에서 분리하고 싶을 때

카운터 컴포넌트 예제

1. 상태 변수 활용하는 방법

const Counter = () => {
  const [count, setCount] = useState(0);
  const changeCount = (e) => setCount(count + Number(e.target.innerText));
  return (
    <>
      <div>
        현재 카운터 값은 <b>{count} 입니다.</b>
      </div>
      <div>
        <button onClick={changeCount}>+1</button>
      </div>
      <div>
        <button onClick={changeCount}>-1</button>
      </div>
    </>
  );
};

setCount(count + Number(e.target.innerText));
버튼 안의 내용(innerText)를 Number() 이용해서 숫자로 바꿔줌

버튼의 내용이 숫자로 변환가능하기 때문에 하나의 핸들러 함수로 구현이 가능한 것

버튼의 내용이 문자열인 경우 ➡️ 숫자로 변환할 수 없음 ➡️ 핸들러 함수를 따로 작성해야 함

2. reduce 이용하는 방법

리듀스 함수 생성

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

state:현재 상태변수
action: 상태변수 변경에 필요한 조건과 값 (호출 시 전달되는 값)


const Counter = () => {
  const [state, disptch] = useReducer(reducer, { count: 0 });
  
  return (
    <>
      <div>
        현재 카운터 값은 <b>{state.count} 입니다.</b></div>
      <div>
        <button onClick={() => disptch({ type: "INCREMENT" })}>하나 더하기</button>
      </div>
      <div>
        <button onClick={() => disptch({ type: "DECREMENT" })}>하나 빼기</button>
      </div>
    </>
  );
};

useReducer(reducer, { count: 0 }) 리듀서 함수와 초기 상태를 인자로 받음
const [state, disptch] 상태값과 디스패치 함수 반환

onClick={() => disptch({ type: "INCREMENT" })}
액션을 리듀서로 전달해서 상태를 업데이트

여러 입력창의 상태를 관리

1. useState 이용하는 방법

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

  const changeName = (e) => setName(e.target.value);
  const changeNickname = (e) => setNickname(e.target.value);

  return (
    <>
      <div>
        <p>이름:{name} </p>
        <p>별명: {nickname}</p>
      </div>
      <div>
        <p>
          이름: <input type="text" value={name} onChange={changeName} />
        </p>
        <p>
          별명: <input type="text" value={nickname} onChange={changeNickname} />
        </p>
      </div>
    </>
  );
};

2. useReducer를 이용하도록 변경

리듀서 함수 정의

action = { type: 변경할 상태변수, value: 변경할 값 }
액션의 구조는 내가 지정함
dispatch() 함수를 호출할 때 action 값을 설정해서 전달


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


  return (
    <>
      <div>
        <p>이름:{state.name} </p>
        <p>별명: {state.nickname}</p>
      </div>
      <div>
        <p>
          이름: <input type="text" value={state.name} onChange={(e)=>dispatch({type:"name", value:e.target.value})} />
        </p>
        <p>
          별명: <input type="text" value={state.nickname} onChange={(e)=>dispatch({type:"nickname", value:e.target.value})} />
        </p>
      </div>
    </>
  );
};

const [state,dispatch]=useReducer(reducer,{name:"",nickname:""}); 리듀서함수와 초기 상태를 인자로 받아서 상태값과 디스패치 함수 반환

onChange={(e)=>dispatch({type:"name", value:e.target.value})}
이벤트 객체를 인자로 받고, 디스패치 함수 호출
action값 설정 type:"name" 으로 지정, value: 이벤트 객체의 value

입력창에 name 속성을 추가해서 리듀서 함수와 이벤트 핸들러 함수를 단순화

onChange 함수에 disaptch 함수를 각각 적용해주었는데 name 속성을 추가하면 changeValue 함수를 이용해 한번에 관리할 수 있음

const reducer = (state, action) => {
  /*
    case "name":
      return { ...state, name: action.value };

    case "nickname":
      return { ...state, nickname: action.value };

    default:
      return state;
  }*/
  return {...state,[action.type]:action.value};
};

간소화된 코드

0개의 댓글