본문 바로가기
React

[React] 성능 최적화 비법 공개! 리렌더링 줄이고 속도 개선하기 🧠

by 다다면체 2024. 12. 30.
728x90
반응형

React 애플리케이션을 개발하다 보면 성능 문제가 발생할 때가 있습니다. 특히 컴포넌트의 불필요한 리렌더링은 앱 속도를 저하시킬 수 있는데요, 오늘은 이를 해결하기 위한 성능 최적화 방법과 React에서 제공하는 도구들을 알아보겠습니다! 💡


반응형

1. 리렌더링 최적화의 중요성 🧐

React는 상태나 props가 변경되면 컴포넌트를 리렌더링하는 방식으로 동작합니다. 하지만 모든 리렌더링이 필요한 것은 아니죠. 불필요한 리렌더링을 줄이면 애플리케이션의 성능을 크게 개선할 수 있습니다.

리렌더링이 발생하는 이유

  1. 부모 컴포넌트가 리렌더링될 때 자식 컴포넌트도 리렌더링됨.
  2. props나 상태(state)가 변경될 때.
  3. 동일한 데이터를 다시 계산하거나 처리할 때.

2. React.memo로 컴포넌트 메모화하기 🧠

React.memo는 컴포넌트를 메모화(memoization)하여 동일한 props가 전달되면 이전 결과를 재사용하도록 합니다.

예제: React.memo 사용하기

import React from 'react';

const ChildComponent = React.memo(({ value }) => {
  console.log('ChildComponent Rendered');
  return <div>Value: {value}</div>;
});

function ParentComponent() {
  const [count, setCount] = React.useState(0);
  const [text, setText] = React.useState('');

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
      <ChildComponent value={count} />
    </div>
  );
}

export default ParentComponent;

이 코드의 동작

  1. ChildComponent는 value props가 변경될 때만 리렌더링됩니다.
  2. React.memo를 사용하지 않으면 text가 변경될 때도 리렌더링이 발생합니다.

3. useMemo로 값 메모화하기 📦

useMemo는 계산 비용이 높은 연산을 메모화하여 불필요한 재계산을 방지합니다.

예제: useMemo 사용하기

import React, { useMemo, useState } from 'react';

function ExpensiveComponent({ number }) {
  const expensiveCalculation = useMemo(() => {
    console.log('Calculating...');
    return number * 2;
  }, [number]);

  return <div>Result: {expensiveCalculation}</div>;
}

function App() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
      <ExpensiveComponent number={count} />
    </div>
  );
}

export default App;

이 코드의 동작

  1. number가 변경될 때만 expensiveCalculation이 다시 실행됩니다.
  2. 입력값이 변경되어도 메모된 결과를 재사용합니다.

4. useCallback으로 함수 메모화하기 ✨

useCallback은 함수를 메모화하여 동일한 함수를 재사용하도록 합니다. 이를 통해 자식 컴포넌트로 전달되는 함수를 최적화할 수 있습니다.

예제: useCallback 사용하기

import React, { useState, useCallback } from 'react';

const ChildComponent = React.memo(({ onClick }) => {
  console.log('ChildComponent Rendered');
  return <button onClick={onClick}>Click Me</button>;
});

function ParentComponent() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

export default ParentComponent;

이 코드의 동작

  1. handleClick은 메모화되어 동일한 참조를 유지합니다.
  2. ChildComponent는 부모 컴포넌트가 리렌더링돼도 다시 렌더링되지 않습니다.

5. 실제 사례: 무한 스크롤 구현하기 📜

성능 최적화의 대표적인 예로 무한 스크롤이 있습니다. 데이터를 불러올 때 필요한 부분만 로드하여 성능을 개선할 수 있습니다.

예제: 무한 스크롤 구현

import React, { useState, useEffect } from 'react';

function InfiniteScroll() {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(1);

  useEffect(() => {
    const fetchItems = async () => {
      const newItems = Array.from({ length: 10 }, (_, i) => `Item ${i + 1 + (page - 1) * 10}`);
      setItems((prevItems) => [...prevItems, ...newItems]);
    };

    fetchItems();
  }, [page]);

  const handleScroll = () => {
    if (window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight) {
      setPage((prevPage) => prevPage + 1);
    }
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  return (
    <div>
      <h1>Infinite Scroll</h1>
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

export default InfiniteScroll;

이 코드의 동작

  1. 스크롤이 하단에 도달하면 page 상태가 업데이트됩니다.
  2. page가 변경될 때마다 새로운 데이터를 불러옵니다.
  3. 기존 데이터는 유지하면서 새 데이터를 추가합니다.

6. 마무리 🎉

React 애플리케이션의 성능 최적화는 사용자 경험을 개선하는 중요한 단계입니다. 오늘 배운 React.memo, useMemo, useCallback을 활용하면 불필요한 리렌더링을 줄이고 더 빠르고 효율적인 애플리케이션을 만들 수 있습니다. 🚀

실제 프로젝트에서 이런 기법을 적용해보고, 더 나은 성능을 경험해보세요! 💪

728x90
반응형