리액트 #7 useReducer

해기·2022년 11월 4일
0

useReducer는 useState의 setState처럼 상태관리의 관한 기능인데
useReducer를 사용하는 이유는 컴포넌트에서 분리를 시켜줄 수 있다
다른 파일에 작성 후 불러와서 사용도 가능하다.
또한 여러 상태관리들을 한번에 관리도 가능한거같다.

이렇게 복잡하고 긴 상태변화 함수를 컴포넌트 밖으로 관리하는 방법이다.

간단한 예제로 useState로 1에서 10000까지 더하는 기능을 만들었을 때

이렇게 되었을 때 컴포넌트의 코드 길이도 늘어나고 복잡해질 수 밖에없다.
이렇게 복잡하고 무겁게 사용하는건 좋지않은 방법이라 알려주신다. 그럼 이 코드를 useReducer를 사용하면

useReducer를 사용하면 reducer를 컴포넌트 밖에 분리를 해서 다양한 상태변화 로직을
스위치 케이스 문법으로 처리해 줄 수 있다.
사용방법을 알아보면 오른쪽의
[count,dispatch] = useReducer(reducer, 1); 이 부분을 보면
useState를 사용하듯이 배열을 반환하고 [count,dispatch] 사용할 땐 비구조할당으로 사용한다.

첫번째로 반환받게되는 [count]는 State이다. 그래서 이 State는 useState에서 썼던것처럼
div태그 안에 {count}로 똑같이 사용할 수 있다.

두번째로 반환받게되는 [dispatch] 는 상태를 변화시키는 액션을 발생시키는 함수라 생각하면 된다.

세번째로 useReducer(reducer,1); 부분을 보면 (reducer)라는 함수를 반드시 전달해줘야함
dispatch로 상태변화를 일으켰을 때 (reducer)가 처리해주는 역할을 하게된다.

네번째로 useReducer(reducer,1) < - 1은 count State에 초기값이다. 그렇기에
div태그에 있는 {count}는 1이출력이 된다.

이제 버튼부분을 보면
dispatch를 호출하는데 이때 객체를 보내주게된다. 이 객체에는 꼭 type이라는 프로퍼티를 보내줘야한다. 그리고 이 객체를 Action객체라한다.(상태변화)
dispatch가 호출이되면 상태변화가 일어나야하고 그 상태변화에 대한 처리는 reducer가 실행한다.

이제 reducer를 한번 보면
두개의 파라미터를 받는데 state,action
state는 가장 최신의 state를 받아오고
action은 dispatch를 호출할 때 전달해줬던 action객체를 전달받는다. (버튼의 객체로된 type)

그래서 이제 add 1 이라는 버튼을 누르게되면 reducer함수가 실행이되는데 이때
reducer가 받는 state는 1이되고 (현재State는1이라서)
action객체는 type : 1 이라는 객체를 받게됨

그리고 reducer는 switch case문을 이용해서 action.type에 따라 각각 다른 값을 반환한다.
그리고 그 반환한 값은 새로운 State가 된다.

그렇기 때문에 add 1 버튼을 누르면

add 1의 type은 1이니 case1인 저 부분을 실행하게되는데
state는 최신값인 1이 들어있으니 1+1을 반환하게 되는셈이다. 그리고 그 업데이트된 값은
2가되어 count로 들어가게된다.

사용방법과 설명에 대해서는 여기까지고 프로젝트를 만들어뒀던 일기장의 함수들을
reducer로 줄여보자.


이녀석들인데 이녀석들을 reducer로 줄여보기위해 일단

useReducer를 만들어주고 reducer를 호출한 뒤 data의 초기값인 빈배열을 넣어준다.
(원래 사용하던 data State는 주석처리)

App컴포넌트 밖에 reducer 함수를 생성해주고 파라미터로 state와action을 받아준다.

그리고 안에 switch case문을 미리 작성해두고, (type이름을 미리지정해둠)

순서대로
INIT = 초기의 데이터( 일기20개 ) api받아와서 출력할 함수
CREATE = 글 작성 함수
REMOVE = 글 삭제 함수
EDIT = 글 수정 함수
그리고 switch case 문에서는 default 케이스를 반드시 지정해주어야해서
reducer는 항상 새로운 state를 return해주어야하는 의무가 있음.
그래서 default 일땐 type을 잘못전달 할 수 있으니 상태를 변화시키지않도록
return state;으로 state를 그대로 전달해주면 값이 안바뀌기게된다

INIT CREATE REMOVE EDIT을 하나씩 바꿔보면

getData 함수안에
dispatch를 넣어서 dispatch를 실행하겠다 라는걸 알려주고
type을 'INIT' 으로 지정해준 뒤 뒤에 INIT 액션에 필요한 데이터를 전달해준다.
data:initData = 위 initData 함수를 전달해줌
이제 setData는 삭제해도됨 그 역할을 dispatch가 하기때문

위에 switch case의 INIT부분에 State를 변화시킬 코드를 입력해줌
왜 action.data냐면 아래 dispatch에서 data로 initData를 받아오기때문에
return action.data = 새로운 State가 된다. (빈 배열이 initData가 됨 20개의 일기데이터)

다음 CREATE부분을 바꿔보면

(뒷부분이 짤렷는데 id : dataId.current임)
그리고 created_date는 현재 시간을 뽑아주는거라 case에서 작성하기로 함
이제 아래의 newItem부분과 created_date는 필요가없어졌으니 지워도 됨
setData또한 마찬가지로 삭제해도 됨

(dataId는 함수밖에 useRef(0)로 만들어준거라 삭제하지않고 dataId.current += 1;도 남겨놓음)

이제 onCreate에서 dispatch를 실행해주고 action객체로 type은 "CREATE", data는 author,content,emotion id: dataId.current를 전달해준다.

switch문에서 보면

시간을 기록해주는 created_date를 만들어주고
newItem이라는 객체에 ...action.data 라는 스프레드연산자로 아이템들을 뿌려주고 created_date도 추가해줌
그래서 newItem이라는 객체에는 author, content, emotion id: dataId.current, created_date 가 들어있는 셈
이 배열을 새로운 State값으로 사용하면 된다.

return [newItem, ...state] 로 newItem을 state에 추가해줌 (create완성)

이번엔 onRemove를 보면

여기에서는 똑같이 dispatch를 실행해주고 type을 REMOVE로 지정해주고
data는 targetId를 보내줌 (targetId와 같다면 지워라 라는걸 구현하기때문)
setData는 삭제해주고 Switch로 가서

REMOVE일땐 action.targetId와 같은 id를 가진녀석을 지우면 됨
그냥 필터함수 사용한다 생각하면 됨.

마지막으로 EDIT


EDIT에서도 dispatch를 호출하고 type EDIT으로 지정해주고 targetId와 newContent를 전달해줌 Switch로 가서

똑같이 map함수를 사용하여 state내의 아이템들에 targetId와 같은 요소를 찾은 뒤
만약 Id가 같다면 ...it으로 다른건 그대로 남겨두고 content부분만 newContent로 바꿔달라 해주고
아이디가 다른요소들은 그대로 it 남겨줘라 라고 구현을 해줌

이제 완성이 됐다.

useReducer는 이해하기가 쉽지않았어서 이 강의만 4번째 봤더니 이제 이해가 좀 되는것 같다..

profile
프론트엔드 개발 공부중, 글쓰는데 재주가없음

0개의 댓글