[React Hooks 총정리] useReducer

혜빈·2024년 7월 12일
0

REACT 보충개념

목록 보기
34/48

useReducer

  • useState처럼 State를 생성하고 관리할 수 있게 해주는 도구
  • 여러개의 하위 값을 포함하는 복잡한 State를 다뤄야 할 때 useState 대신 useReducer를 사용하면 훨씬 간결하게 코드 작성 가능
  • 유지보수도 편해짐
  • Reducer, Dispatch, Action 세가지로 이루어짐

Reducer, Dispatch, Action

  • 여름이가 은행에서 만원을 출금했다고 생각하기
  • 여름이가 은행을 방문해서 "만원을 출금해주세요"라고 요구하면 여름이의 계좌 거래내역에서 만원이 빠져나갔다고 기록이 됨
  • 여름이는 직접적으로 자신의 거래내역을 업데이트 시키지 않음 -> 여름이는 은행에게 요구를 하고 은행은 여름의 요구에 따라 거래내역을 업데이트 해줌
  • 거래내역을 State라고 생각하기
  • 은행을 Reducer라고 생각하기
  • 여름이가 은행에게 거래내역을 업데이트 해달라고 하는 행위를 Dispatch라고 생각하기
  • "만원을 출금해주세요"라는 요구 내용을 Action이라고 생각하기

Reducer (은행 역할)

  • State를 업데이트 해주는 역할
  • Component의 State를 변경하고 싶다면 꼭 Reducer를 통해야 함
  • 여름이가 거래내역을 업데이트 하고 싶으면 은행이 대신 해줘야 하는 것과 같음

Dispatch (여림이의 요구 행위)

  • 여름이가 은행에게 거래내역을 업데이트 해달라고 하는 행위와 같음

Action (요구 내용)

  • "만원을 출금해주세요"라는 요구 내용이 Action임

정리

  • 여름이는 은행에게 요구라는 Dispatch 안에 내용이라는 Action을 담아서 은행이라는 Reducer에 보냄으로써 State를 변경할 수 있음

  • 여름이가 거래내역이라는 State를 업데이트 하기 위해선 요구라는 Dispatch에 "만원을 출금해주세요"라는 내용인 Action을 넣어서 은행이라는 Reducer에 전달을 해줘야 함

  • 그럼 은행은 Action의 내용대로 State를 업데이트 시켜줌

  • 여름이는 은행이라는 Reducer에게 다른 Action들을 보냄으로써 예금, 출금, 송금 등 복잡한 일을 할 수 있음

컴포넌트의 관점으로 보기

  • State를 업데이트 시켜주기 위해서는 Dispatch 함수의 인자로 Action이라는 것을 넣어서 Reducer에게 전달을 해줌
  • 그럼 Reducer가 컴포넌트의 State를 Action안의 내용대로 업데이트 시켜줌

실제 코드 구현

  • useReducer는 useState와 비슷하게 배열을 반환해줌
  • 배열의 첫 번째 요소 : 새로 만들어진 State
  • 배열의 두 번째 요소 : useReducer가 만들어준 dispatch 함수

  • useReducer는 두 개의 인자를 받음
  • 첫 번째 인자 : reducer (새로 생성해줘야 함)
  • 두 번째 인자 : 배열의 첫 번째 요소의 새로 만들어진 State에 들어갈 초기값

  • reducer는 두 개의 인자를 받음
  • 첫 번째 인자 : 현재 State
    reducer 함수가 불리는 시점에 useReducer 배열의 첫 번째 요소인 새로 만들어진 State 안에 들어간 값이 들어가게 됨
  • 두 번째 인자 : action
    reducer에게 State를 변경해달라고 요구할때 그 요구에 대한 내용이 들어감

  • money State는 reducr를 통해서만 수정 가능
  • money를 수정하고 싶을 때마다 dispatch를 불러줌
  • dispatch는 useReducer가 만들어준 함수, 사용할 때 인자로 action을 넣어줌
  • dispatch를 부르면 reducer가 호출이 됨 -> 인자로 action이 전달이 됨 -> action을 토대로 reducer는 Stete를 변경해줌

  • action은 보통 objcet 형태로 보내고, 그 안에 type을 넣음
  • type안에는 reducer에게 요구하고 싶은 내용을 넣으면 됨
  • payload 안에는 현재 input에 들어있는 값을 넣어주기

  • reducer가 action에 나와있는대로 State를 업데이트 시켜주도록 코드 작성
  • reducer가 return하는 값이 새로 업데이트 될 State가 됨

  • useReducer도 useState와 같이 State가 바뀔 때마다 컴포넌트를 렌더링 해줌

  • 우리는 예금, 출금 모두 구현해야 하기 때문에 항상 state + action.payload를 사용하면 안됨

  • action안에 들어있는 type에 따라 다르게 state를 업데이트 해줘야 함

  • 그래서 보통 reducer안에 if else 문 또는 switch문을 많이 사용함


만약 코드를 더 깔끔하게 만들고 싶다면?

  • action의 type을 따로 constant로 빼주면 됨
  • constant 내의 문자열만 수정해주면 나머지도 다 업데이트가 되기 때문에 유지/보수에 편리함

기존 코드

변경 코드

실행 화면

1) 예금 버튼 클릭시

2) 출금 버튼 클릭시


실제 코드 구현 2

UseReducerHook2

import React, { useReducer, useState } from "react";
import Student from "../components/Student";

const reducer = (state, action) => {};

// 초기 State
const initalState = {
  // 학생 수
  count: 0,
  students: [
    {
      id: Date.now(),
      name: "been",
      // 출석을 하지 않음을 표시
      isHere: false,
    },
  ],
};

function UseReducerHook2() {
  const [name, setName] = useState("");
  const [studentInfo, dispatch] = useReducer(reducer, initalState);

  return (
    <div>
      <h1>출석부</h1>
      <p>총 학생 수 : {studentInfo.count}</p>
      <input
        type="text"
        placeholder="이름을 입력해주세요"
        value={name}
        // input이 달라질때마다 name State 업데이트
        onChange={(e) => setName(e.target.value)}
      ></input>
      <button>추가</button>
      {/* 각 학생들을 Student 컴포넌트로 만들어줌
      prop으로 name을 줘서 student name을 가져옴 */}
      {studentInfo.students.map((student) => {
        return <Student key={student.id} name={student.name} />;
      })}
    </div>
  );
}

export default UseReducerHook2;

Student

import React from "react";

const Student = ({ name }) => {
  return (
    <div>
      <span>{name}</span>
      <button>삭제</button>
    </div>
  );
};

export default Student;


학생 추가하는 기능 만들기

  • studentsInfo 안에 students를 넣어주면 됨
  • state를 변경하는거니까 reducer 안에서 코드 수정

  • 추가버튼에 add-student type의 action을 담은 dispatch 설정해주기

  • reducer에서 switch문 사용해서 조건 설정해주기

  • 새로운 학생이 잘 추가됨

  • initialState에서 been은 필요 없으니까 student를 빈 배열로 바꿔주기

  • switch문에 default, delete-student case 추가해주기

  • student 컴포넌트의 prop으로 dispatch 보내주기

  • Student 컴포넌트에 가서 dispatch와 id 받기
  • 삭제 버튼에 dispatch를 불러서 type과 payload 설정해주기

  • UseReducerHook2 컴포넌트에서 delete-student return 부분 코드 작성해주기

  • 추가 버튼 클릭시 추가 잘 됨

  • 삭제 버튼 클릭시 삭제 잘 됨

학생 출석 여부 기능 구현

  • 출석여부는 isHere 속성 이용

  • UseReducerHook2 파일에서 isHere을 true로 변경해주기
  • Student 컴포넌트에 student.isHere 보내주기

  • Student 파일로 가서 prop에 isHere 받아주고 span태그 style 속성 변경해주기

  • onClick 속성을 통해 학생의 이름을 클릭할때마다 true -> false, false -> true로 바뀌게 해주기

  • reducer에 가서 mark-student case 추가해주기

  • isHere도 false로 바꿔주기


  • 이름 클릭시 style이 잘 적용이 됨
  • 이름을 다시 클릭하면 style이 해제됨
profile
최강 개발자를 꿈꾸는 병아리

0개의 댓글