Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- Kotlin
- React #React 사용하는 이유
- 패키지
- React #Context #props drilling #useMemo
- useMemo #React.memo #최적화 #re-rendering
- Common JS 모듈 시스템
- React #API 호출 #async #await #fetch
- useCallback #최적화 #함수형 업데이트
- useReducer
- Node.js #
Archives
- Today
- Total
세현's 개발로그
[React] 복잡한 상태 관리 로직 분리하기 - useReducer (feat. 일기장) 본문
◈ useReducer
지금까지 작성한 App.js 코드는 useState가 너무 많아 컴포넌트 내의 내용이 너무 복잡하다는 문제가 있다.
이를 해결하기 위해 useReducer를 사용하여 상태변화로직을 App.js컴포넌트로부터 분리한다.
useReducer는 const [data, dispatch] = useReducer(reducer, []);
이러한 형식을 사용하는데 이때 배열의 비구조화할당에서 0번째 인자는 항상 state이고, 두 번째 인자는 dispatch이다.
useReducer의 첫 번째 인자는 reducer(상태변화처리함수)이고 두 번째 인자는 state의 초기값이다.
상태변화처리함수인 reducer는 컴포넌트 밖으로 분리하여 직접 만들어줘야 한다.
const reducer = (state, action) =>
{ switch( action.type) {
reducer는 두 개의 파라미터를 가지는데,
첫 번째 파라미터는 상태변화가 일어나기 직전의 현재상태, 두 번째 파라미터는 상태변화에 대한 정보가 들어있는 action 객체이다. 기존에 setData가 했었던 역할을 dispatch와 reducer가 나눠서 수행하도록 만들어준다.
App.js
import React, {
useCallback,
useEffect,
useMemo,
useReducer,
useRef
} from "react";
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList";
import "./App.css";
const reducer = (state, action) => {
switch (action.type) {
case "INIT": {
return action.data;
}
case "CREATE": {
const created_date = new Date().getTime();
const newItem = {
...action.data,
created_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;
}
};
const App = () => {
const [data, dispatch] = useReducer(reducer, []);
const dataId = useRef(0);
const getData = async () => {
const res = await fetch(
"https://jsonplaceholder.typicode.com/comments"
).then((res) => res.json());
const initData = res.slice(0, 20).map((it) => {
return {
author: it.email,
content: it.body,
emotion: Math.floor(Math.random() * 5) + 1,
created_date: new Date().getTime(),
id: dataId.current++
};
});
dispatch({ type: "INIT", data: initData });
};
useEffect(() => {
getData();
}, []);
const onCreate = useCallback((author, content, emotion) => {
dispatch({
type: "CREATE",
data: { author, content, emotion, id: dataId.current }
});
dataId.current += 1;
}, []);
const onRemove = useCallback((targetId) => {
dispatch({ type: "REMOVE", targetId });
}, []);
const onEdit = useCallback((targetId, newContent) => {
dispatch({
type: "EDIT",
targetId,
newContent
});
}, []);
const memoizedDiaryAnalysis = useMemo(() => {
const goodCount = data.filter((it) => it.emotion >= 3).length;
const badCount = data.length - goodCount;
const goodRatio = (goodCount / data.length) * 100.0;
return { goodCount, badCount, goodRatio };
}, [data.length]);
const { goodCount, badCount, goodRatio } = memoizedDiaryAnalysis;
return (
<div className="App">
<DiaryEditor onCreate={onCreate} />
<div>전체 일기 : {data.length}</div>
<div>기분 좋은 일기 개수 : {goodCount}</div>
<div>기분 나쁜 일기 개수 : {badCount}</div>
<div>기분 좋은 일기 비율 : {goodRatio}%</div>
<DiaryList diaryList={data} onRemove={onRemove} onEdit={onEdit} />
</div>
);
};
export default App;
'React' 카테고리의 다른 글
[React] 컴포넌트 트리에 데이터 공급하기 (feat. 일기장) (1) | 2023.05.07 |
---|---|
[React] useCallback() 최적화 (feat. 일기장) (0) | 2023.05.07 |
[React] useMemo(), React.memo 최적화(feat. 일기장) (0) | 2023.05.07 |
[React] React에서 API 호출하기 (0) | 2023.05.06 |
[React] React Lifecycle 제어하기 - useEffect (0) | 2023.04.30 |
Comments