[REACT] useReducer - 복잡한 상태변화 로직 분리

짱효·2023년 11월 13일
0

REACT

목록 보기
18/29
post-thumbnail

복잡한 상태변화 로직 분리

  • app 컴포넌트: 복잡한 로직(많은 상태변화 함수)
  • 많은 데이터들이 있다.
  • 컴포넌트가 무거워지는건 안좋아 함수들을 밖으로 분리할 것이다.

useReducer

  • 리액트 상태관리를 관리한다.
  • 상태 뱐허ㅣ 를 컴포넌트에서 분리 가능

  • 컴포넌트, 상태관리 변수가가 엄청 많아 질 수 있다.

상태 변화 로직 분리하기



useReducer 사용

  1. useState 지우고 App 컴포넌트 밖에 Reducer 사용

  2. data에 어떤 타입의 액션들이 필요한지 탐색

  3. setState 지우기

  • oncreate

import { useRef, useEffect, useMemo, useCallback, useReducer } from "react";
import "./App.css";
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList";
// import OptimizeTest from "./OptimizeTest";
//1️⃣ 외부에 reducer함수를 넣는다.
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;
  }
};

function App() {
  //1️⃣ useState 주석처리한다.
  // const [data, setData] = useState([]);
  //1️⃣ useReducer
  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,
        //Math.floor 정수로 바꿔줌, 0~4여서 +1 해줌
        emotion: Math.floor(Math.random() * 5) + 1,
        created_date: new Date().getTime(),
        // id 만들기. useRef 의 .current
        id: dataId.current++,
      };
    });
    //1️⃣ dispatch로 바꾸기
    dispatch({ type: "INIT", data: initData });
    //1️⃣ 지우기
    // setData(initData);
  };

  //라이프 사이클, 컴포넌트가 생성되면
  useEffect(() => {
    // 데이터를 가져온다.
    getData();
  }, []);

  //새로운 데이터를 추기하는 함수
  // useMemo는 값을 반환하는것이여서 안됨.
  const onCreate = useCallback((author, content, emotion) => {
    //1️⃣dispatch 사용
    dispatch({
      type: "CREATE",
      data: { author, content, emotion, id: dataId.current },
    });
    //1️⃣ 주석
    // const created_date = new Date().getTime();
    // const newItem = {
    //   author,
    //   content,
    //   emotion,
    //   created_date,
    //   //어떤 돔도 가르키지 않고 0이라는 값을 가지고있다.
    //   id: dataId.current,
    // };
    dataId.current += 1;
    //함수형 업데이트: 상태변환 함수에 함수를 넣어준다.
    // 항상 최신의 값
    //1️⃣ 주석
    // setData((data) => [newItem, ...data]);
  }, []);

  // useCallback으로 최적화
  const onRemove = useCallback((targetId) => {
    dispatch({ type: "REMOVE", targetId });
  }, []);

  const onEdit = useCallback((targetId, newContent) => {
    dispatch({ type: "EDIT", targetId, newContent });
    //함수형으로 바꿔주기
    // setData((data) =>
    //   //  it아이디가 맞으면 content에 새로운 내용을 넣어준다(삼항연산자)
    //   data.map((it) =>
    //     it.id === targetId ? { ...it, content: newContent } : it
    //   )
    // );
  }, []);

  //일기 감정 분석 함수
  //useMemo
  // 이건 함수가 아니라 값이다.
  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 길이가 변하면 업데이트 됨.
  }, [data.length]);

  //함수를 연산자로 변수로 나누기
  // useMemo는 함수로 말고 값으로 사용해야한다.getDiaryAnalysis() (x) =>getDiaryAnalysis
  const { goodCount, badCount, goodRatio } = getDiaryAnalysis;

  return (
    <div className="App">
      <DiaryEditor onCreate={onCreate} />
      <div>전체 일기 : {data.length}</div>
      <div>기분 좋은 일기 개수: {goodCount}</div>
      <div>기분 나쁜 일기 개수: {badCount}</div>
      <div>기분 좋은 일기 비율: {goodRatio}</div>
      <DiaryList onEdit={onEdit} onRemove={onRemove} diaryList={data} />{" "}
      {/* 더미 리스트 프롭스로 전달 */}
    </div>
  );
}

export default App;
profile
✨🌏확장해 나가는 프론트엔드 개발자입니다✏️

0개의 댓글