티스토리 뷰

728x90

😎 React에서 리렌더링이 되는 조건

  • state 변경이 있을 때
  • 전달받은 props 값이 업데이트 되는 경우
  • 부모 컴포넌트가 렌더링 될 때
    • 부모 컴포넌트가 렌더링되면, 모든 자식 컴포넌트를 순차적으로 리렌더링 하게 됨
  • forceUpdate가 실행될 때

 

 

😎 React에서 렌더링 성능 최적화 방법

1. useMemo, useCallback 훅

useMemo와 useCallback에 대한 상세한 내용은 아래에 기재되어 있습니다.

 

2. React.memo 컴포넌트 메모이제이션

  • React.memo는 훅이 아니기 때문에 클래스형 컴포넌트에서도 사용할 수 있다.
  • React.memo를 사용하면 컴포넌트의 props가 바뀌지 않았다면, 리렌더링하지 않도록 설정하여 렌더링 성능을 최적화 할 수 있다.

3. 컴포넌트 맵핑 시 key값으로 index 사용하지 않기

배열 중간에 어떤 요소가 삽입되면 그 중간 이후 위치한 요소들은 전부 index가 변경되기 때문에 리마운트가 일어나야 한다.

또한 리액트는 key값이 동일할 때 동일한 DOM Element를 보여주기 때문에 예상치 못한 문제가 발생할 수 있다.

4. state 선언 위치

렌더링의 수행 조건으로 state 값의 변화가 있는데 state가 변경이 되면 선언된 컴포넌트와 하위 컴포넌트들이 모두 리렌더링 된다.

그래서 해당 state를 사용하는 최상단 컴포넌트에 선언하여 불필요한 리렌더링을 줄이는게 좋다.

 

 

 

😎 useMemo와 useCallback

useMemo

 

메모이제이션된 값을 반환한다. useMemo(() => fn, deps)

 

함수형 컴포넌트의 경우 컴포넌트 렌더링 -> Component 함수 호출 -> 모든 내부 변수 및 함수 초기화 의 순서를 거칩니다.

만약 특정 변수가 함수의 실행을 통해 연산이 되는 경우, 컴포넌트 렌더링이 일어날 때마다 변수를 계산하는 함수가 호출되게 됩니다. 만약 연산 함수의 시간이 오래 걸린다면 사용성이 저하되게 될 것입니다.

 

useMemo를 사용하면 매 렌더링마다 함수를 호출하지 않고, 연산에 필요한 값이 변경되는 필수적인 경우에만 연산을 수행하여 이러한 문제를 해결할 수 있습니다.

 

function MyComponent({x, y}) {
	// useMemo 사용하지 않은 경우
	const z = compute(x, y);
    // useMemo 적용
    const z = useMemo(() => compute(x,y), [x, y]);
	return <div>{x}</div>;
}
const id = useMemo(() => (router.query?.questionId ? parseInt(router.query.questionId as string, 10) : null), [router.query]);

useMemo는 첫 번째 인자로 콜백함수를, 두번째 인자로 의존성 배열을 받습니다.

useMemo의 두번째 파라미터로 넣은 deps 배열이 바뀌면 우리가 등록한 함수를 연산하고, 바뀌지 않았다면 이전에 연산한 값을 재사용하게 됩니다.

 

그런데 값을 재활용하기 위해 따로 메모리를 소비해서 저장을 해 놓는 것이기 때문에, 불필요한 값을 모두 Memoization 하면 성능이 저하될 수 있습니다. 또한 프론트엔드에서 수초 이상 걸리는 로직이 존재하는 경우가 흔치 않아서, 리렌더링이 심각한 성능 이슈로 이어지는 경우는 흔치 않기 때문에 useMemo가 필요한 경우에 사용합시다!

 

useCallback

 

메모이제이션된 함수를 반환한다. useCallback(() => fn, deps)

 

함수를 메모이제이션하기 위해서 사용되는 hook입니다. 

React 컴포넌트의 렌더링이 일어날 때마다 새로운 함수가 생성되게 됩니다.

그래서 이러한 문제를 해결하기 위해 useCallback을 사용하면 컴포넌트가 렌더링 되더라도 함수가 의존하는 배열 내의 값이 변경되지 않으면 기존 함수를 재사용합니다.

const add = () => x + y; // useCallback 적용 전, 렌더링될 때마다 새로운 함수가 생성됨
const add = useCallback(() => x + y, [x, y]); // useCallback 적용, x 또는 y 값이 변경될 때만 새로운 함수가 생성됨

 

 

useCallback 사용하는 경우

의존 배열로 함수를 넘길 때

자바스크립트에서는 함수도 객체로 취급되기 때문에 메모리 주소에 의한 참조가 일어나게 됩니다.

useEffect 함수는 두 번째 인자로 넘어온 의존 배열이 변경될 때만 첫 번째 인자로 전달된 함수를 호출합니다.

아래 예시에서 fetchUser 함수가 변경될 때만 API를 호출하도록 설계했습니다.

하지만 fetchUser는 함수이므로 컴포넌트가 렌더링이 될 때마다 새로운 참조값으로 변경이 됩니다. 그러면 useEffect 함수가 호출되어 user 값이 바뀌고, 그러면 다시 렌더링이 일어나도 다시 useEffect...가 호출되는 악순환이 반복됩니다.

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

function Profile({ userId }) {
  const [user, setUser] = useState(null);

  const fetchUser = () =>
    fetch(`https://your-api.com/users/${userId}`)
      .then((response) => response.json())
      .then(({ user }) => user);

  useEffect(() => {
    fetchUser().then((user) => setUser(user));
  }, [fetchUser]);

  // ...
}

 

그래서 이와 같은 상황에 useCallback 훅을 사용하면 컴포넌트가 다시 렌더링되더라도 fetchUser 함수의 참조값을 유지시킬 수 있습니다.  따라서 useEffect()에 넘어온 함수는 userId의 값이 변경되지 않는 한 재호출되지 않게 됩니다.

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

function Profile({ userId }) {
  const [user, setUser] = useState(null);

  const fetchUser = useCallback(() =>
    fetch(`https://your-api.com/users/${userId}`)
      .then((response) => response.json())
      .then(({ user }) => user),
      [userId]
  )

  useEffect(() => {
    fetchUser().then((user) => setUser(user));
  }, [fetchUser]);

  // ...
}

 

 

😎 React의 생명주기메서드 (LifeCycle Method)

리액트의 클래스형 컴포넌트에서 사용하는 메서드

 

http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

마운트

  • constructor : 컴포넌트의 생성자 메서드. 컴포넌트가 만들어지면 가장 먼저 실행됨
  • getDerivedStateFromProps : 컴포넌트의 props나 state가 바뀌었을 때 호출되는 메서드, 처음 렌더링 되기 전에도 호출이 되고 그 이후 리렌더링이 일어날 때도 실행됨
  • render : 컴포넌트를 렌더링하는 메서드
  • componentDidMount : 컴포넌트의 첫번째 렌더링이 끝나고 호출되는 메서드, 컴포넌트에서 필요로 하는 데이터를 axios, fetch등을 통해 요청하거나 DOM의 속성을 읽거나 변경하는 작업을 진행함

 

업데이트

  • getDerivedStateFromProps 
  • shouldComponentUpdate : 컴포넌트가 리렌더링을 할지 말지를 결정하는 메서드. 최적화 할 때 사용하는 메서드로, React.memo와 비슷한 역할을 함
  • render
  • getSnapshotBeforeUpdate : 컴포넌트에 변화가 일어나기 직전의 DOM 상태를 가져와서 특정 값을 반환하면 그 다음 발생하는componentDidUpdate 함수에서 받아서 사용할 수 있음
  • componentDidUpdate : 리렌더링이 끝나고 화면에 변경 사항이 모두 반영되고 난 뒤 호출되는 메서드. getSnapshotBeforeUpdate에서 반환된 값을 조회할 수 있음

 

언마운트

컴포넌트가 화면에서 사라지는 것

  • componentWillUnmount : 컴포넌트가 화면에서 사라지기 직전에 호출됨, DOM에 직접 등록한 이벤트를 제거하고, setTimeout같은 것을 clearTimeout을 통해 제거합니다.

 

 

😎 References

https://seungddak.tistory.com/109

 

[react] 리렌더링이 되는 조건들 살펴보기

state 변경이 있을 때 - react 에서 유동적인 데이터를 저장하기 위해서 state 라는 것을 이용한다. 이때 state 값을 바꿔주기 위해서는 state 를 직접 조작해서는 안되고 setState() 메서드를 이용해 주어

seungddak.tistory.com

https://www.daleseo.com/react-hooks-use-callback/

 

React Hooks: useCallback 사용법

Engineering Blog by Dale Seo

www.daleseo.com

https://react.vlpt.us/basic/17-useMemo.html

 

17. useMemo 를 사용하여 연산한 값 재사용하기 · GitBook

17. useMemo 를 사용하여 연산한 값 재사용하기 이번에는 성능 최적화를 위하여 연산된 값을 useMemo라는 Hook 을 사용하여 재사용하는 방법을 알아보도록 하겠습니다. App 컴포넌트에서 다음과 같이 co

react.vlpt.us

https://react.vlpt.us/basic/25-lifecycle.html

 

25. LifeCycle Method · GitBook

25. LifeCycle Method LifeCycle Method 는 한국어로 "생명주기 메서드" 라고 부릅니다. 생명주기 메서드는 컴포넌트가 브라우저상에 나타나고, 업데이트되고, 사라지게 될 때 호출되는 메서드들 입니다.

react.vlpt.us

https://cocoder16.tistory.com/36

 

리액트 렌더링 최적화하는 8가지 방법과 고찰

서론 이 글은 함수형 컴포넌트, 클래스형 컴포넌트 상관없이 공통적으로 적용되는 렌더링 최적화 이야기와 hooks를 사용하는 함수형 컴포넌트에서 구체적으로 어떤 기능들을 사용해 렌더링 최적

cocoder16.tistory.com

 

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함