React 기초공부 -7

솔다·2023년 2월 18일
0

useMemo() 활용하기

성능 최적화를 위해 사용하는 useMemo() 함수를 사용해보자.

useMemo의 첫번째 파라미터에는 어떻게 연산할지 정의하는 함수를 넣어주면 되고, 두번째 파라미터에는 deps배열을 넣어주면 되는데, 이 배열 안에 넣은 내용이 바뀌면, 우리가 등록한 함수를 호출해서 값을 연산해주고, 만약에 deps내용이 바뀌지 않았다면, 이전에 연산한 값을 재사용하게 됩니다.

useCallback() 활용하기

useMemo()와 매우 비슷해보이는데 무엇이 다를까?

크게 다르지는 않지만, 사용하는 경우가 조금 다르다. useCallback()은 특정 함수를 새로만들지 않고 재사용하고 싶을때 사용합니다.

const onCreate = () => {
  const user = {
    id: nextId.current,
    username,
    email
  };
  setUsers(users.concat(user));

  setInputs({
    username: '',
    email: ''
  });
  nextId.current += 1;
};

위의 코드를 보면(원본은 출처를 통해서 예제 전체 코드를 확인가능하다.) 이 함수들이 예제에서 컴포넌트가 리렌더링 될 때마다 새로 만들어진다. 함수를 선언하는 것 자체는 크게 리소스를 차지하지는 않지만, 함수를 필요할 때만 새로 만들고 재사용하는 것은 중요하다.
(userssetUserssetState()로 만들어진 것이다.)

아래에 useCallback()을 적용한 코드를 보자

 const onCreate = useCallback(() => {
    const user = {
      id: nextId.current,
      username,
      email
    };
    setUsers(users.concat(user));

    setInputs({
      username: '',
      email: ''
    });
    nextId.current += 1;
  }, [users, username, email]);

주의할 점은 함수 안에서 사용하는 state혹은 props가 있다면 꼭 deps배열 안에 포함시켜야 한다. 위의 예시에는 [users, username, email]이 포함되어 있는 것을 볼 수 있다. 만일값을 넣지 않게 되면 함수에서 사용하는 값들이 가장 최신의 값이라는 보장을 못하게 된다.

React.memo 로 리렌더링 방지하기

이 함수는 컴포넌트의 props 가 바뀌지 않은 경우에 리렌더링을 방지하여 리렌더링 성능 최적화를 해줄 수 있는 React.memo 라는 함수를 알아보도록 하자.

이 함수는 사용방법이 매우 간단한데, 리렌더링이필요한 시점에만 리렌더링 되도록 만들 수 있다.

위에서 만들었던 CreateUser 부분의 코드에 적용하는 것을 보자.

import React from 'react';

const CreateUser = ({ username, email, onChange, onCreate }) => {
  return (
    <div>
      <input
        name="username"
        placeholder="계정명"
        onChange={onChange}
        value={username}
      />
      <input
        name="email"
        placeholder="이메일"
        onChange={onChange}
        value={email}
      />
      <button onClick={onCreate}>등록</button>
    </div>
  );
};

export default React.memo(CreateUser);

위처럼 따로 component로 분리하고 단순하게 React.memo()로 감싸주면 된다.

그리고 이외에도 더 추가적으로 최적화를 하고 싶다면?

deps에 users를 가지고 있는 요소들이 리렌더링 되는 것을 방지하기 위해서 할 수 있는 방법이 있지 않을까.

정답은 함수형 업데이트이다.

아래에 예시가 있다.

const onRemove = useCallback(id => {
    setUsers(users.filter(user => user.id !== id));
  },
  [users]
);
  const onRemove = useCallback(id => {
    setUsers(users => users.filter(user => user.id !== id));
  }, []);

setUsers()안에 업데이트를 할때 함수형으로 값을 넣는 차이를 볼 수 있다. 이렇게 하면 callback()함수의 파라미터에서 최신 users()를 참조할 수 있기 때문에, deps에 users를 넣지 않아도 된다.

추가적인 최적화 기법

이런 기능들을 사용해서 리액트를 최적화하면 컴포넌트의 성능을 개선할 수 있다. 그런데, 리렌더링을 막을 수 없는 경우에는 굳이 사용하지 않는게 맞다. 추가적으로는 React.memo에서 두번째 파라미터에 propsAreEqual이라는 함수를 사용해서 특정 값만 비교하는 것도 가능하다.

export default React.memo(
  UserList,
  (prevProps, nextProps) => prevProps.users === nextProps.users
);

하지만 이를 잘못 사용하면 버그들이 발생할 수 있다. 지금 위쪽에서 우리가 함수형 업데이트로의 전환으로 변경을 해줬는데, 위에처럼 users만 비교를 하게 되면 다른 함수에서 users를 참조하지 않으므로 심각한 오류가 발생할 수 있다.

0개의 댓글