내일배움캠프[4기_Reac트랙]/TIL

내일배움캠프 React트랙 34일차 회고 (2022.12.16)

ecoEarth 2022. 12. 16. 21:14
  • 구조분해할당

useReducer의 개념

상태를 관리하게 될 때 useState 를 사용하는것 말고도 다른 방법이 있다. 바로 useReducer 라는 Hook을 사용하는것인데, 이 Hook 함수를 사용하면 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다. 상태 업데이트 로직을 컴포넌트 바깥에 작성 할 수도 있고, 심지어 다른 파일에 작성 후 불러와서 사용 할 수도 있다.

즉, 다른 컴포넌트에서도 재사용을 하기위해 로직을 따로 정의할 수 있어, 유지보수에 유리하고 간결한 코드를 내보일 수 있다는 장점이 있다.


useReducer의 사용방법

const [state, dispatch] = useReducer(reducer, initialState);

useReducer 에 넣는 첫번째 파라미터는 reducer 함수이고, 두번째 파라미터는 초기 상태이다.

여기서 state 는 우리가 앞으로 컴포넌트에서 사용 할 수 있는 상태를 가르키게 되고, dispatch 는 액션을 발생시키는 함수라고 이해하면 된다.

dispatch({ type: 'INCREMENT', 액션객체에 보낼정보1, 액션객체에 보낼정보2  })

다음과 같이 작성하면 따로 작성해둔 액션이 발생된다.


useReducer의 사용예제

person.reducer.js (분리된 로직)

export default function personReducer(person, action) {
  switch (action.type) {
    case "updated": {
      const { prev, current } = action;
      return {
        ...person,
        mentors: person.mentors.map((mentor) => {
          if (mentor.name === prev) {
            return { ...mentor, name: current };
          }
          return mentor;
        }),
      };
    }
    case "added": {
      const { name, title } = action;
      return {
        ...person,
        mentors: [...person.mentors, { name, title }],
      };
    }
    case "deleted": {
      return {
        ...person,
        mentors: person.mentors.filter((mentor) => mentor.name !== action.name),
      };
    }
    default: {
      throw Error(`알수없는 액션 타입이다: ${action.type}`);
    }
  }
}
  • 이러한 분리된 로직은 reducer함수를 사용할 컴포넌트파일 하단부에 같이 작성해두어도 된다.

 

const { prev, current } = action;
// 구조분해할당이다. 아래의 두줄을 동시에 쓴것과 같은 의미이다.
const prev = action.prev;
const current = action.current;
  • 구조분해할당이 쓰였다.

AppMentors.jsx (분리해둔 로직 가져와 활용)

import React, { useReducer } from "react";
import personReducer from "./reducer/person-reducer";

export default function AppMentor() {
  const [person, dispatch] = useReducer(personReducer, initialPerson);

  const handleUpdate = () => {
    const prev = prompt(`누구의 이름을 바꾸고 싶은가요?`);
    const current = prompt(`이름을 무엇으로 바꾸고 싶은가요?`);
    dispatch({ type: "updated", prev, current });
  };

  const handleAdd = () => {
    const name = prompt(`멘토의 이름은?`);
    const title = prompt(`멘토의 직함은?`);
    dispatch({ type: "added", name, title });
  };

  const handleDelete = () => {
    const name = prompt(`누구를 삭제하고 싶은가요?`);
    dispatch({ type: "deleted", name });
  };

  return (
    <div>
      <h1>
        {person.name}는 {person.title}
      </h1>
      <p>{person.name}의 멘토는:</p>
      <ul>
        {person.mentors.map((mentor, index) => (
          <li key={index}>
            {mentor.name} ({mentor.title})
          </li>
        ))}
      </ul>
      <button onClick={handleUpdate}>멘토의 이름을 바꾸기</button>
      <button onClick={handleAdd}>멘토 추가하기</button>
      <button onClick={handleDelete}>멘토 삭제하기</button>
    </div>
  );
}

const initialPerson = {
  name: "당신",
  title: "개발자",
  mentors: [
    {
      name: "밥",
      title: "시니어개발자",
    },
    {
      name: "제임스",
      title: "시니어개발자",
    },
  ],
};