• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    미해결

안녕하세요 리액트 최적화 관련하여 질문드립니다.

22.03.30 11:23 작성 조회수 1.17k

2

안녕하세요. 웹 최적화 파트1,2 수강자입니다.
 
수강을 하면서 웹에 대해 최대한 성능 좋게 개발을 꾸준히 하려고 노력하고 있습니다. 이에 따라 여러 가지 고민이 되는 부분이 생겨서 해당 카테고리와는 크게 관련성은 없지만 여기에 글을 올려봅니다.
 
궁금증 1.
 
useMemo, useCallback 관련하여 질문드리고 싶습니다.
 
memoization을 통해 불필요한 렌더링을 줄일 수 있는 장점을 가지고 있어 위와 같은 훅을 잘 사용해보려합니다. 하지만 효율적으로 사용을 해야 메모리 적으로 봤을 때 문제가 되지 않을거같아 고민을 하는 찰라에 많은 개발자분들이 단순히 useState에서 set하는 부분만을 useCallback에 담아서 사용하는거 같더라구요.
 
예를 들어
const [ isOpen, setIsOpen = useState<boolean>(false);
const callback = useCallback( () => {setIsOpen(true)}, []);
 
이런 식으로요.
 
하지만 제 생각에는 이렇게 작은 것도 다 넣으면 모든게 메모리에 올라가게 되어 메모리 낭비인가 라는 생각이들었습니다.
이러한 작은 것들도 다 useMemo나 useCallback 을 적용하는 것이 메모리적인 관점에서 보는 것보다 렌더링에 이점을 주는 것이 더 큰가라는 생각이 듭니다.
 
혹시 이 부분에 대해 피드백 해주시면 감사하겠습니다.
 
궁금증 2.
 
많은 input에서의 onChange에 따른 렌더링
 
회원가입 폼과 같이 input 굉장히 많은 경우 여기에 onChange Event에 따라 회원정보가 set이 되고 타이핑할 때마다 리렌더링이 된다는 생각이 과하다는 생각이들어서 질문 드립니다.
 
그래서 제가 생각해본건 useRef로 모든 input에 접근하고 회원가입 버튼 눌렀을 때 한번에 input value 를 가져와서 한번만 set을 하는게 낫지않을까 라는 생각도 들었습니다.
 
위와 같은 생각이 잘못되었는지, 혹은 onChange에 따라 set을 다해도 가상돔으로 비교해서 전체 다 그려주는게 아니기 때문에 큰 이슈는 되지않아 그냥 사용해도 될지에 대해 궁금합니다.
 
답변해주시면 정말 감사하겠습니다.
 

답변 1

답변을 작성해보세요.

3

안녕하세요, 유상원님,

둘 다 좋은 질문을 해주셨습니다.
이 부분에 대해서는 저도 항상 고민하는 부분인데요, 제 생각 위주로 답변드리겠습니다.

1. 

말씀하신대로 무분별한 memoization은 오히려 메모리를 낭비하게 됩니다.
useCallback과 useMemo를 사용하는 이유는 매번 렌더링마다 새로운 객체(함수 또는 값)를 생성하지 않기 위해서 사용하는 건데요,
예를 들어 반복적으로 리렌더링 되는 컴포넌트의 경우, 내부에서 선언하는 모든 함수나 변수들이 렌더링 시 마다 생성이 됩니다. 이 때, useCallback 또는 useMemo를 사용하여 렌더링 전, 후로 업데이트가 필요없는 함수나 변수에 대해서 불필요한 재할당을 방지할 수 있습니다.

하지만, 아래 코드와 같이 컴포넌트의 리렌더링이 곧 함수의 업데이트로 이어져야 한다면 useCallback을 사용할 필요가 없습니다.

function Component({ title }) {
  const handleClick = useCallback(() => {
    alert(title);
  }, [title]);

  return <button onClick={handleClick}>{title}</button>;
}

위 코드에 대해서 설명드리면, Component라는 컴포넌트가 리렌더링 되는 경우는 props로 내려오는 title이 변경되는 경우입니다. 그리고 그 안의 handleClick 함수는 title을 디펜던시로 가지고 있어서 title이 변경된 경우 함수를 업데이트합니다. 즉, Component가 리렌더링 되면 handleClick 함수는 항상 업데이트가 되는거죠.
다시 말해, handleClick 함수가 재활용되는 경우는 없습니다. 그렇기 때문에 useCallback 훅을 사용할 필요도 없는 거고요.

정리하면, 
memoization 기능을 사용할 때는 memoization 후, 얼마나 재활용이 가능한 것인가를 잘 따져봐야 합니다.
위의 예시와 같이 한 번도 재활용이 안 되는 경우라면 오히려 memoization을 사용하면 안 되겠죠.
재활용이 된다고 해도 얼마나 많이 재활용이 될 것인가도 따져볼 수 있습니다. 100번의 리렌더링에서 1번만 재활용되는 값을 굳이 memoization을 할 필요는 없습니다. 이 기준은 해당 값의 특성과 중요도를 잘 따져보고 결정하시면 될 것 같습니다.

 

2.

Controlled Component와 Uncontrolled Component에 대해서 검색해보시길 추천드립니다.

말씀하신 대로 ref를 이용해서 특정 시점(완료버튼을 눌렸을 때와 같은)에서만 state를 업데이트 하실 수 있습니다.
하지만, 만약 값의 입력에 따라 화면의 일부 요소가 변해야 한다고 하면 얘기가 달라집니다.
예를 들어 타이핑 시, 글자 수를 보여준다거나 하는 식으로요.

만약 그런 식으로 매번 state를 업데이트해야한다고 하면 최대한 컴포넌트를 작은 단위로 분리하여 리렌더링에 대한 비용을 줄이고,
매번 리렌더링 되는 컴포넌트 안의 값들을 memoization 해두는 것도 좋습니다.

 

그럼 답변이 도웁되셨길 바라며, 강의에 관심을 가져주셔서 감사합니다. :)

유상원님의 프로필

유상원

질문자

2022.03.30

자세한 답변 정말 감사합니다. 답변에 대해 고려해보면서 앞으로 코드를 짜보도록 하겠습니다. 감사합니다.