2 분 소요

💎 상태 변화 로직 분리하기

  • count: state
  • dispatch: 상태를 변화시키는 액션을 일으키는 함수 -> type 프롭이 들어있는 객체를 전달
  • reducer: 상태 변화를 처리해주는 함수

이 객체는 상태에 대한 객체이다.

total Code

import "./App.css";
import { useRef, useEffect, useMemo, useCallback, useReducer } from "react";
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList";

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) =>
        TimeRanges.id === action.targetId
          ? { ...it, content: action.newContent }
          : it
      );
    }

    default:
      return state;
  }
};
function App() {
  // const [data, setData] = useState([]);

  const [data, dispatch] = useReducer(reducer, []);

  const dataId = useRef(0);

  /* 새로운 리스트 추가 */
  const onCreate = useCallback((author, content, emotion) => {
    dispatch({
      type: "CREATE",
      data: { author, content, emotion, id: dataId.current },
    });

    dataId.current += 1;
  }, []);

  /* 기존 추가된 리스트 삭제 */
  const onRemove = (targetId) => {
    dispatch({ type: "REMOVE", targetId });
  };

  /* 데이터 수정 */
  const onEdit = (targetId, newContent) => {
    dispatch({ type: "EDIT", targetId, newContent });
  };

  /* API 호출하기 */
  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 });
  };

  // Mount 시점에 수행
  useEffect(() => {
    getData();
  }, []);

  /* emotion 점수 카운팅 */
  const getDiaryAnalysis = useMemo(() => {
    const goodCount = data.filter((it) => it.emotion >= 3).length;
    const badCount = data.length - goodCount;
    const goodRatio = (goodCount / data.length) * 100;
    return { goodCount, badCount, goodRatio };
  }, [data.length]);

  const { goodCount, badCount, goodRatio } = getDiaryAnalysis;

  return (
    <div className="App">
      <h1>일기장</h1>
      <DiaryEditor onCreate={onCreate}></DiaryEditor>
      <div className="diaryAnalysis">
        <h2> 전체 일기 : {data.length}</h2>
        <div>기분 좋은 일기 개수 : {goodCount}</div>
        <div>기분 나쁜 일기 개수 : {badCount}</div>
        <div>기분 좋은 일기 비율 : {goodRatio}% </div>
      </div>
      <DiaryList
        diaryList={data}
        onRemove={onRemove}
        onEdit={onEdit}
      ></DiaryList>
    </div>
  );
}

export default App;

🔆 코드 분석

기존에 useState를 사용해서 state가 변경될 때마다 data를 변경시켜주어서 사용했다. 그래서 이렇게 사용한 함수가 onCreate, onRemove, onEdit, getData 가 있다.

하나의 컴포넌트에 여러개의 함수들이 역할을 한다는 것은 그닥 좋지 않으므로 useReducer를 사용해서 역할을 분리해주는 것이다. => then HOW?

기존 useState자리에

const [data, dispatch] = useReducer(reducer, []);

으로 변경시켜준다. 진행과정은 dispatch를 통해서 어떤 type인지 액션 객체가 reducer로 전달이 되고, 거기서 리턴된 값이 data로 넘어가는 형식이다.

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) =>
        TimeRanges.id === action.targetId
          ? { ...it, content: action.newContent }
          : it
      );
    }

    default:
      return state;
  }
};

state는 현재 변경되기 전 state를 말하고, action은 action 객체를 말한다. 기존의 함수들에서 사용되었던 변수들을 action 객체를 통해서 전달해주면 된다.

태그:

카테고리:

업데이트:

댓글남기기