React

React_기초다지기_하루정리(최적화 1 - 연산 결과 재사용)

SanL 2023. 5. 30. 01:55

React


⚑목표 : 연산 결과값을 재사용 하는 방법!

  • 현재일기 데이터를 분석하는 함수를 제작하고, 해당함수가 일기 데이터의 길이가
    변화하지 않을 때 값을 다시 계산하지 않도록 한다
  • Memoization 이해하기

[Memoization 이란?]

이미 계산 해 본 연산 결과를 기억해 두엇다가
동일한 계산을 시키면, 다시 연산하지 않고 기억해 두었던 데이터를 반환 시키게 하는 방법

//마시 시험을 볼때, 이미 풀어본 문제는 다시 풀어보지 않아도 답을 알고 있는 것과 유사한 느낌.


[useMemo : 연산 최적화]

  1. useMemo의 사용방법 : 우리가 Memoization해주고 싶은 함수를 감싸주면됨
    즉, useMemo는 첫번째 인자를 콜백함수로 받아서 콜백함수가 retrun하는 값들을 최적화할 수 있도록 도와주는 그런 기능을 한다.
    또한, 두번째 파라미터는 useEffect와 같이 의존성 배열을 받게 되는데, []안에 들어간 어떤 상태의 값이 변하게 되면 콜백함수를
    실행하게 되고, 만약 그렇지 않으면 콜백함수는 랜더링 되지않음
    <또한, useMemo라는 함수는 어떤 함수를 전달받아서 콜백함수가 리턴하는 값을 다시 리턴하게되는 것 !> 최적화된 함수를 가져다 쓸
    경우에는 ()로 받는 것이 아니라 함수명, 값으로 받는다.
  2. 어떤 함수가 있고, 그 함수가 어떤 값을 리턴하고 있는 경우, 리턴까지의 값을 최적하고 싶을 떄가 있다.
    (어떤 정보를 수정할 때, 랜더링 하지 않아도되는 부분까지 지속적으로 불필요한 랜더링이 되는 경우 등이 발생할 수 있음)
    이럴떄 useMemo를 통해 값을 최적화 할 수 있음.

[일기 리스트 정보 출력]

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

function App() {
  const [data, setData] = useState([]); //우리는 여기에 일기 리스트를 저장할 것이기 때문에 빈배열

  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++,
      };
    });
    setData(initData);
  };

  useEffect(() => {
    getData();
  }, []);

  //리스트에 작성하는 작성자, 감정, 내용들을 onCreate를이용하여 저장
  const onCreate = (author, content, emotion) => {
    const created_date = new Date().getTime();
    const newItem = {
      author,
      content,
      emotion,
      created_date,
      id: dataId.current,
    };
    dataId.current += 1; // dataId가 하나씩 증가하도록 만들어줌
    setData([newItem, ...data]); // 원래 있던 데이터에 새로운 아이템을 이어서 출력할 수 있음
  };

  const onRemove = (targetId) => {
    console.log(`${targetId}가 삭제되었습니다.`);
    const newDiaryList = data.filter((it) => it.id !== targetId);
    setData(newDiaryList); // 특정 targetId를 가진 부분만을 제외하고 다시만든 배열은 존달해줌
  };

  const onEdit = (targetId, newContent) => {
    // 특정 데이터를 수정하는 함수
    setData(
      data.map((it) =>
        it.id === targetId ? { ...it, content: newContent } : it
      )
    );
  };

  const getDiaryAnalysis = useMemo(() => {
    console.log("일기 분석 시작");

    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">
      <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;

// 일기 정보의 길이가 변화할때만, getDiaryAnalysis함수의 값이 반환되고, 이렇게 되면 랜더링의 횟수를 줄이고
최적화를 할 수 있음