솔미는 성장중

오히려 컴포넌트를 나눴더니 성능이 떨어진다? : 컴포넌트 최적화하기 (reactMemo & useCallback & useMemo) 본문

react

오히려 컴포넌트를 나눴더니 성능이 떨어진다? : 컴포넌트 최적화하기 (reactMemo & useCallback & useMemo)

solming 2023. 8. 25. 05:28
728x90

문제 상황

오히려 컴포넌트를 나눴더니 성능이 떨어진다? 

이것은 렌더링이 최적화되어있지 않기 때문이다.

props가 변화하는 곳만 렌더링 해주면 되는데 전부 다 렌더링하고 있는 경우 이런 현상이 발생한다.

 

해결법

React.memo

컴포넌트를 React.memo()로 둘러싸면 컴포넌트를 메모이징한다.

props가 바뀌지 않은 컴포넌트는 새롭게 렌더링되지 않고 메모이징 된 내용을 재사용한다.

 

언제 사용하면 좋을까?

- 새로 업데이트를 잘 시키지 않아도 되는 컴포넌트

 

예시

const List = React.memo(({ posts, testFunction }) => {
  console.log("List Component");

  return (
    <ul>
      {posts.map((post) => (
        <ListItem key={post.id} post={post} />
      ))}
    </ul>
  );
});

 

useCallback

함수 자체를 메모이징 한다.

 

왜 사용할까?

- 최적화

- 처리 시간을 빠르게 하기 위해 코드를 효율적으로 처리하게 만들어준다.

- 컴포넌트가 새롭게 렌더링 된다해서 똑같은 함수를 계속 다시 만드는 것은 비효율적.(해당 함수를 내려받은 자녀 컴포넌트도 새롭게 렌더링 되게 때문에..) -> 이러한 함수는 재생성하지 않게 만들어준다.

 

언제 사용하면 좋을까?

- 해당 함수를 다른 컴포넌트로 내려줬을 때

- 의존성 배열[ ]가 자주 바뀌지 않을 때

 

useMemo

함수의 리턴값을 메모이징한다.

(useCallback과 매우 유사)

 

언제 사용하면 좋을까?

- 함수 내에서 heavy한 계산을 하는 경우

 

 

성능 비교 예제 코드) A는 통으로 작성, B는 컴포넌트화 (+최적화된 상태)

 

App.js

import "./App.css";
import { useEffect, useState } from "react";
import A from "./components/A";
import B from "./components/B";

function App() {
  const [value, setvalue] = useState("");

  //jsonplaceholder 데이터를 GET하기 위한 요청 보내기
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    //백엔드 api에 요청보내기
    //비동기 요청
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((response) => response.json())
      .then((posts) => setPosts(posts)); //데이터 기억 => state사용
  }, []); // 종속성 배열에 아무것도 없으면 한번만 실행

  return (
    <div style={{ padding: "2rem" }}>
      <input value={value} onChange={(e) => setvalue(e.target.value)} />
      <div style={{ display: "flex" }}>
        <A message={value} posts={posts} />
        <B message={value} posts={posts} />
      </div>
    </div>
  );
}

export default App;

 

A.js

import React from "react";

const A = ({ message, posts }) => {
  return (
    <div>
      <h1>A Component</h1>
      <p>{message}</p>
      <ul>
        {posts.map((post) => {
          return (
            <li key={post.id}>
              <p>{post.title}</p>
            </li>
          );
        })}
      </ul>
    </div>
  );
};

export default A;

 

B.js

import React, { useCallback } from "react";

const Message = React.memo(({ message }) => {
  console.log("Message Component");
  return <p>{message}</p>;
});

const ListItem = React.memo(({ post }) => {
  console.log("ListItem Component");
  return (
    <li>
      <p>{post.title}</p>
    </li>
  );
});

const List = React.memo(({ posts, testFunction }) => {
  console.log("List Component");

  return (
    <ul>
      {posts.map((post) => (
        <ListItem key={post.id} post={post} />
      ))}
    </ul>
  );
});

const B = ({ message, posts }) => {
  console.log("B component");
  const testFunction = useCallback(() => {}, []); //B컴포넌트 렌더링 => testFunction 함수 재생성 => List 자녀 Props => List 컴포넌트 렌더링
  return (
    <div>
      <h1>B Component</h1>
      <Message message={message} />
      <List posts={posts} testFunction={testFunction} />
    </div>
  );
};

export default B;

 

 

728x90