-
🤷♀️ useReducer
- 상태관리를 돕는 리액트 훅스
- 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수
- useState 대체 가능 => 상태변화 로직들을 컴포넌트에서 분리하여 컴포넌트를 가볍게 작성할수있다.
🤷♀️ 사용방법
const [state, dispatch] = useReducer(reducer, 1);
비구조화 할당을 통해서 사용하며, 0번째 인덱스는 state, 1번째 인덱스는 상태를 변화시키는 액션을 발생시키는 함수를 넣어주면 된다.
또한, useReducer함수 호출시 dispatch가 상태변화를 일으킬때 일어난 상태변화를 처리해주는 reducer 함수를 꼭 전달해줘야 하며, 두번째 인자로 전달하는 값은 state의 초기값이 된다.
const reducer = (state, action) { // 새로운 상태를 만드는 로직 // const nextState = ... // return nextState; // switch (action.type) { // case 'CASE_NAME': // return { // ...state, // inputs: { // ...state.inputs, // [action.name]: action.value // } // }; // default: // return state; // } }
reducer 에서 반환하는 상태는 곧 컴포넌트가 지닐 새로운 상태가 되며, 여기서 action은 업데이트를 위한 정보를 가지고 있는데 주로 type 값을 지닌 객체 형태로 사용한다.
😏 분리해보자
1. App 컴포넌트 기존 작성한 useState 주석처리 (useReducer를 사용하기 위해)
2. useReducer 추가 (import 체크)
const [data, dispatch] = useReducer(reducer,[]);
0번째 state인 data 두번째는 항상 dispatch
3. App 컴포넌트 밖에 reducer 함수 생성
const reducer = (state, action) => {};
상태변화가 일어나기 직전의 state. 어떤상태변화를 일으켜야하는지에대한 정보가 담긴 action객체
4. action객체에 담긴 type 프로퍼티를 통해 switch를 이용해 상태변화를 처리
dispatch가 호출되면 reducer가 실행되고 reducer가 리턴하는 값이 data의 값이 된다.
5. 액션이 일어나는 각 함수에 reducer 호출 해주기
액션의 타입과 액션에 필요한 데이터 넣어서. 기존 진행 호출 지워주기
const initData = res.slice(0,20).map((it) => { return { author : it.email, content : it.body, emotion : Math.floor(Math.random() * 5)+1, create_date : new Date().getTime(), id : dateId.current++ } }); dispatch({type:'INIT', data:initData}); //setData(initData); };
const onCreate = useCallback((author, content, emotion) => { dispatch({type:'CREATE',data:{author, content, emotion, id:dateId.current}}); // const create_date = new Date().getTime(); // const newItem = { // author, // content, // emotion, // create_date, // id : dateId.current // }; dateId.current += 1; //setData((data) => [newItem, ...data]); },[] );
const onRemove = useCallback((targetId) => { dispatch({type:'REMOVE',targetId}); //setData(setData => data.filter((it) => it.id !== targetId)); },[]);
const onEdit = useCallback((targetId, newContent) => { dispatch({type:'EDIT', targetId, newContent}); // setData((data) => // data.map((it) => it.id === targetId ? {...it, content: newContent} : it) // ); },[]);
6. switch문 작성
const reducer = (state, action) => { switch(action.type) { case 'INIT': { return action.data } case 'CREATE': { const create_date = new Date().getTime(); //받아온 생성 시간값없으니까 다시 추가 const newItem = { ...action.data, create_date } return [newItem, ...state]; } case 'REMOVE': { return state.filter((it) => it.id !== action.targetId); } case 'EDIT': { return state.map((it) => it.id === action.targetId ? {...it, content: action.newContent} : it); } default: return state; } };
✋ dispatch는 함수형 업데이트 필요없이 호출을 하면 알아서 현재의 state를 reducer 함수가 참조하여 자동으로 그렇게 해주니까 useCallback을 쓰면서 디펜던시 어레이를 걱정하지 않아도 된다.
Demo : winterlood - codesandbox
'Blog > React.js' 카테고리의 다른 글
[일기장 만들기_15] 컴포넌트 트리에 데이터 공급 (Context) (0) 2022.03.05 [일기장 만들기_13] 최적화 완성 (0) 2022.03.01 [일기장 만들기_12] 최적화 3 - useCallback 🙄 (0) 2022.02.24 [일기장 만들기_11] 최적화 2 - React.memo (컴포넌트 재 사용) (0) 2022.02.24 [일기장 만들기_10] 최적화 1 - useMemo (연산 결과 재사용) (0) 2022.02.23 댓글