[Udemy] React 기본 - 일기장 만들기(9) 최적화1 (연산결과 재사용) : useMemo

productuidev·2022년 5월 2일
0

React Study

목록 보기
28/52
post-thumbnail
post-custom-banner

React 기본 (Project)

Udemy - 한입크기로 잘라 먹는 리액트


📌 일기장 만들기 (9) - 최적화1 (연산결과 재사용) : useMemo

☑️ 연산 결과값을 재사용하는 방법

☑️ Memoization 기법

  • 프로그래밍 기법에 가까운 이야기
  • 이미 계산해본 결과를 기억해 두었다가 똑같은 계산을 시키면 다시 계산하지 않고 그냥 답만 반환하는 방법
  • 포인트 : A라는 문제를 우리가 해결했다는 것이 포인트가 아니라 이 A라는 문제를 풀고 그 답을 외웠다, 기억했다라는 행위 자체에 있음
  • 이 문제에 대한 답을 찾은 적이 있고, 그 답을 또 기억하고 있다면 그냥 기억해 둔 답을 적기만 하면 되는데 시간 아깝게 굳이 이 문제를 다 계산하고 그런다면 낭비..!
  • 이런 상황을 Memoization을 이용해서 연산 최적화를 위해 이 문제에 대한 답을 이전에 기억해 두었다는 뜻

☑️ 사람과 컴퓨터의 차이

  • 컴퓨터는 기억 용량에 한계가 있긴 하지만 인간보다 훨씬 월등한 용량을 가지고 있음
  • 프로그래밍을 하다가 답을 기억하는 이런 Memoization 기법을 통해 문제를 해결하게 되는 경우가 많음
  • 이런 Memoization 기법을 리액트 프로그래밍을 진행하면서 어떤 부분에 어떻게 적용해야 하는지 알아보기

☑️ 일기장 프로젝트의 감정점수를 활용한 Memoization

  • emotion이라는 감정점수를 기록할 수 있는 기능 (1~5까지의 감정)
  • 1에 가까울수록 감정이 안 좋음(bad) 5에 가까울수록 감정이 좋음(good)

☑️ getDiaryAnalysis 함수

✔️ App 컴포넌트에 지금 현재 dataState가 가지고 있는 일기들 중

  • 기분이 좋은 일기가 현재 몇 개인지
  • 기분이 나쁜 일기가 현재 몇개인지
  • 기분 좋은 일기의 비율은 어떻게 되는지
    → 이 3가지의 data를 구하는 getDiaryAnalysis 함수 만들기

src/App.js

function App() {
  const [data, setData] = useState([]);
  
  const getDiaryAnalysis = () => {
      console.log("일기 분석 시작"); // 콘솔에 출력
  
  		// 1) 기분 좋은 일기가 몇 개인지 세는 상수
        // 내장함수 filter 적용 : 이 배열의 원소 중에 감정점수가 3 이상인 것만 추리고 그 길이를 구하면 개수가 나옴
        const goodCount = data.filter((it) => it.emotion >= 3).length;

		// 2) 기분 나쁜 일기가 몇 개 인지 세는 상수
        // 전체 개수 빼기 기분 좋은 일기
		const badCount = data.lenght - goodCount;
        
        // 3) 기분 좋은 일기 비율을 구하는 상수
        // 전체 개수 분의 기분 좋은 일기 곱하기 100
        const goodRatio = (goodCount / data.length) * 100;
        
        // 1~3)의 데이터를 객체로 리턴해주기
        return {goodCount, badCount, goodRatio};
  
	
    // 만들어진 지역함수를 리턴 전에 호출
	// 객체로 리턴하니까 똑같이 객체의 비구조화 할당으로 받기
    // const {goodCount, badCount, goodRatio} = getDiaryAnalysis();
  };
   
   // DOM에 기분 좋은/나쁜 일기 개수, 기분 좋은 일기 비율 렌더링
  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>
  );
  
}

☑️ useMemo로 연산최적화하기

  • getDiaryAnalysis 함수가 호출될 때마다 콘솔에 "일기 분석 시작"을 출력하게 했는데, 몇 번 출력됐는지 확인하게 되면 해당 함수가 2번 동작하는 것을 확인할 수 있음

✔️ 왜 두 번 동작했을까?

  • App 컴포넌트가 처음 Mount될 때 dataState 값은 빈 배열임
  • 그 순간 getDiaryAnalysis 함수를 한 번 호출하게 됨
  • 그 다음 getData API 호출이 성공하고, setData가 이루어지게 되면서 data가 한 번 바뀌게 됨. 그러면 App이 다시 리렌더링됨. 그러면 모든 함수들이 재생성됨
  • 그러면서 const {goodCount, badCount, goodRatio} = getDiaryAnalysis();가 다시 생성되면서 호출이 되게 되므로 결과적으로 두 번 동작하게 됨.
  • 리렌더링이 일어난다는 의미 : 함수가 호출된다, 재실행
  • 일기 수정하기 : 수정 시 dataState가 또 바뀌기 때문에 "일기 분석 시작"이 또 출력됨

  • 일기 데이터를 수정하는 행위는 일기 개수/비율 계산에 아무런 영향을 미칠 수 없음.
    감정점수를 수정하는 게 아닌 작성내용만 수정하는 건데도 App 컴포넌트가 리렌더링되어 함수가 재호출되고 있는 낭비

  • 이런 리턴을 가진 함수를 Memoization을 통해 연산 최적화를 위해 useMemo 활용하기

src/App.js

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

function App() {
  const [data, setData] = useState([]);
  
  // useMemo 연산최적화
  const getDiaryAnalysis = useMemo(() => {
      console.log("일기 분석 시작");
  
      const goodCount = data.filter((it) => it.emotion >= 3).length;
      const badCount = data.lenght - goodCount;
      const goodRatio = (goodCount / data.length) * 100;
      return {goodCount, badCount, goodRatio}; // return을 가진 함수를 최적화
    }, [data.length]); // dependency array

  const {goodCount, badCount, goodRatio} = getDiaryAnalysis; // 호출이 아닌 값으로 변경
}
  • useMemo의 두번째 인자인 []data.length 넣어놓게 되면 전체 일기가 변화할 때만 useMemo의 첫번째 인자인 콜백함수가 다시 수행되게 됨
  • getDiaryAnalysis 함수를 호출한다하더라도 전체 일기(data.lenght)가 변하지 않는 이상 똑같은 리턴을 계산하지 않고 반환한다는 의미
  • 처음 이야기한 시험 문제를 이미 풀어놓으면 답을 기억해서 그냥 똑같은 문제를 만났을 때 그 답을 그냥 적기만 하면 된다와 같은 논리
  • const {goodCount, badCount, goodRatio} = getDiaryAnalysis;는 useMemo로부터 값을 리턴받기 때문에 getDiaryAnalysis 함수를 호출하지 않고 값으로 사용해야 함.

✔️ 연산 최적화 확인

  • 임의의 일기 데이터 1개를 수정해도 전체 일기 수가 변경된 것이 아니기 때문에 콘솔에 "일기 분석 시작"이 출력되지 않음(다시 함수를 호출하지 않게 됨). 그런데 임의로 1개의 일기를 삭제하면 전체 일기 수가 바뀌어서 다시 "일기 분석 시작"이 출력되면서 연산 최적화가 일어난 것을 확인 가능.

⚡️ 정리

  • 어떤 함수가 있고 그 함수가 어떤 값을 리턴하고 있을 때, 그 리턴까지의 연산을 최적화하고 싶다면 useMemo 훅을 사용해서 두번째 인자인 dependency array []어떤 값이 변화할 때만 이 연산을 다시 수행할 것인지를 명시해주면 이 함수를 값처럼 사용해서 연산 최적화가 가능하다.

📖 Memoization 더 알아보기

  • 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술이다. 동적 계획법의 핵심이 되는 기술.
  • 반복되는 계산이 많을수록 효과가 높아짐. 특히 반복 작업이 많을 경우에는, 숫자가 커질수록 반복 횟수가 기하급수적으로 늘어나는데, 메모이제이션을 사용한 코드 작성 시 사소한 차이가 결과에 엄청난 영향을 미침
profile
필요한 내용을 공부하고 저장합니다.
post-custom-banner

0개의 댓글