iOS 개발자가 React 배우기: useReducer

SteadySlower·2024년 10월 28일
0

React JS

목록 보기
4/13

useReducer를 사용하는 이유

어플리케이션을 만들다가 보면 비슷한 로직을 여러 군데의 뷰에서 같이 사용해야 하는 경우가 생긴다. 이럴 때 이 로직들을 Reducer로 묶어두면 유지 보수하기 쉬워진다. 특히 reducer는 state를 변경하는 로직을 모아두는 곳이다.

SwiftUI에서 하나의 ObservableObject를 만들어두면 여러 View 객체에서 사용할 수 있는 것과 같은 원리라고 생각하면 된다. TCA를 사용해본 적이 있다면 TCA의 reducer를 떠올리면 좋다.

Reducer 만들기

아래 코드 reducer는 학생이라는 state를 관리하는 reducer이다. 일단 reducer는 2개의 인자를 반드시 받아야 한다. 첫번째는 이전의 state이고 두번째는 action이다. 간단히 말해서 state와 action을 조합하여 새로운 상태를 리턴하는 함수라고 생각하면 된다.

action object 안에는 type과 state를 변경하는데 필요한 값들이 들어있다. type은 이 reducer가 state를 어떻게 변경할 것인가가 정의 되어 있다. 이 type을 기준으로 switch문을 사용하는 것이 일반적이다. (TCA와 매우 유사하다!)

그리고 action object 안에 있는 다른 값을 활용해서 새로운 state를 리턴하면 된다. reducer는 state 변경하는 로직이 여러 군데에서 사용이 되고 복잡하거나 자주 변경되는 경우 유용하다.

export default function studentReducer(student, action) {
    switch (action.type) {
        case "changeClass": {
            const { newClass } = action;
            return {
                ...student,
                class: newClass,
            };
        }
        case "subjectAdded": {
            const { name, teacher } = action;
            return {
                ...student,
                subjects: [...student.subjects, { name, teacher }],
            };
        }
        case "subjectDeleted": {
            return {
                ...student,
                subjects: student.subjects.filter(
                    (subject) => subject.name !== action.name
                ),
            };
        }
        default: {
            throw Error(`알수없는 액션 타입이다: ${action.type}`);
        }
    }
}

Reducer 사용하기

reducer를 사용할 때는 state를 사용할 때처럼 [] 안에서 2개의 값을 리턴 받는다. 첫번째는 state 값이고 두번째는 dispatch 함수로 state를 변경할 때 사용한다.

그리고 useReducer에는 2개의 인자를 전달하는데 첫 번째는 reducer 함수를 전달하고 두 번째는 state의 초기 값을 전달한다.

dispatch 함수를 사용할 때는 인자로 object를 전달하는데 이 object가 reducer의 action이다. type과 동시에 reduce에 정의한 인자들을 같이 전달하면 된다.

export default function AppStudent() {
  // 첫번째는 상태, 두번째는 reducer를 사용할 수 있게 해주는 함수
const [student, dispatch] = useReducer(studentReducer, initialStudent);

const handleChangeClass = (newClass) => {
  dispatch({ type: 'changeClass', newClass });
};

const handleChangeSubject = (name, teacher) => {
  dispatch({ type: 'subjectAdded', name, teacher });
};

const handleSubjectDelete = (name) => {
  dispatch({ type: 'subjectDeleted', name });
};

return (
  // view 생략
);
}
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글