
컴포넌트 내부에 새로운 state를 생성하는 리액트 훅
➡️ 모든 useState는 useReducer로 대체 가능
차이점은,
상태 관리 코드를 컴포넌트 외부로 분리 가능하다는 것
useState는 “현재 렌더링 중인 컴포넌트 인스턴스”에 상태를 붙이는데,
컴포넌트 밖(모듈 최상단 등)에서 상태 관리 코드를 쓰면 “어느 컴포넌트의 상태인지” 알 수 없기 때문
따라서 useState를 통해서 state를 생성하면,
onCreate처럼 state를 관리하는 코드, 즉 상태를 관리하는 코드를 컴포넌트 내부에 작성해야 함
useReducer를 사용하면,
컴포넌트 내부에선 state 생성만 하고,
state 관리는 Reducer라는 함수를 통해 컴포넌트 외부에서 관리하도록 코드 분리
이전에는 todo 데이터를 관리하는 state를 App 컴포넌트 내부에서 useState를 통해 만들었음
➡️ todos와 setTodos는 App 컴포넌트에서만 접근 가능
따라서, 이 state를 관리하는 코드 또한 반드시 App 컴포넌트 내부에만 작성이 되어야 했음
문제점‼️
state에 새로운 값을 추가하는 onCreate, 특정 값을 수정하는 onUpdate, 특정 값을 제거하는 onDelete와 같은 todo state를 관리하는 코드들이 App 컴포넌트 내부에 작성되어야 했고,
➡️ 너무 길어지게 됨
여기서 더 복잡하고, 더 다양한 상태 변화를 제공하려면?
컴포넌트 안에 더 긴 코드를 작성해야 함
하지만,
App 컴포넌트의 가장 주된 역할은 UI를 렌더링하는 것임
이와 같이 state를 관리하는 코드가 너무 많아지면 주객전도
UI를 렌더링하는 코드보다 상태를 관리하는 코드가 훨씬 더 길고 복잡하기 때문
➡️ 파일을 열었을 때 코드의 가독성이 떨어지고, 유지보수도 어려움
UI를 렌더링하는 코드와 상태 관리 코드를 분리시키기 위해 useReducer라는 리액트 훅이 필요
테스트를 위한 컴포넌트 생성
이제 해당 컴포넌트에 간단한 카운터 기능 생성
이제 컴포넌트 내부에서 dispatch 함수를 호출하면,
상태 변화가 요청되고
그러면 useReducer가 상태 변화를 실제로 처리하게 될 함수를 호출하게 됨
➡️ 그 함수는 직접 만들어야 함
컴포넌트 바깥에
reducer라는 함수를 만들고,
useReducer에 이렇게 만든 reducer라는 함수를 인수로 넣음(첫 번째 인수)
reducer
: 변환기
➡️ 상태를 실제로 변화시키는 변환기 역할
useReducer의
첫 번째 인수는
위처럼 상태를 실제로 변화시키는 변환기 역할을 하는 reducer라는 함수를 만들어 넣고,
두 번째 인수로는 state의 초기값 전달
따라서,
컴포넌트의 최종적인 useReducer 호출은 위와 같음
이제 버튼을 클릭하면 state값이 1씩 증가하게 해야 함
컴포넌트 내부에서, 버튼이 클릭되었을 때
dispatch 함수를 호출해서 상태 변화를 발송, 즉 요청하게 됨
컴포넌트 안에 onClickPlus라는 함수를 만들어서
버튼의 이벤트 핸들러로 설정
그리고 이 함수 내부에서 dispatch를 호출해서 상태 변화 요청
➡️ 인수로는 상태가 어떻게 변화되길 원하는지 그 정보를 전달할 것
보통 dispatch 안에는 객체 형태의 인수
➡️ + 버튼을 누르면 state값을 1 증가시키길 원함
dispatch로 상태 변화 요청 시
요청 내용: 객체("값을 1만큼 증가시켜줘")
이렇게 인수로 전달되는, 요청의 내용을 담고 있는 객체를
Action 객체라고 함
Action 객체를 인수로 전달하면서, dispatch 함수를 호출하면
useReducer가 요청을 처리하기 위해
실제로 상태를 변화시키는 reducer 함수 호출
reducer 함수의 인수
따라서 매개변수로 받은 state 값과, 액션 객체를 이용해 실제 state 값 변경
🤔 상태 변화 함수도 없는데(to~), 어떻게 state를 변경할 수 있는가?
reducer 함수에서 새로운 state를 반환하기만 하면 됨
그 반환된 값을 useReducer가 불러와서 실제 state 값을 변경시킴
매개변수 action의 type이 "INCREASE"면,
현재 상태 state에 action의 data(1)를 더한 값 반환
-] 버튼
이벤트 핸들러 내 dispatch 안에 객체 전달
reducer 함수에 "DECREASE" 분기 추가
현재 상태 state에 action의 data(1)를 뺀 값 반환
reducer 함수 안에 action의 type이 너무 많아질 것 같으면
switch문으로 작성하는 게 일반적
onCreate, onUpdate, onDelete와 같은 상태변화 함수를 reducer 함수로 옮긴 후,
dispatch 함수만 호출하도록 수정
...item으로 기존의 todo 아이템의 값을 나열하고, 해당 item의 isDone 반전