[FE운영진 스터디] Optimization

꾸Jun·2024년 5월 29일

🦁 멋사 12기

목록 보기
12/16
post-thumbnail

Optimization

Optimization?

Optimization이란 웹 서비스의 성능을 개선하는 모든 행위를 일컫는 말이다.

  • 일반적
    • 서버의 응답속도 개선
    • 이미지, 폰트, 코드 파일 등의 정적 파일 로딩 개선
    • 불필요한 네트워크 요청 줄임
  • React App
    • component 내부의 불필요한 연산, 함수 재생성, 리렌더링 방지

useMemo - 불필요한 연산 방지

"Memoization"이라는 방식을 기반으로 불필요한 연산을 다시 수행하지 않도록 React App을 최적화하도록 도와줌

"Memoization"이란 반복되는 연산을 수행할 때, 계속해서 새로운 연산을 하는 것이 아니라, 저장되어 있던 결과값을 바로 돌려주는 기법을 말한다.

최초에 연산을 해놓은 것을 가지고 남은 연산들에 사용해서 최적화 할 수 있다.

실습

total, done, notDone 개수를 카운트해서, 화면에 렌더링하게 보여주는 코드를 작성한다.

지금 코드는 filter를 사용했으니 item의 개수가 늘어날 수록 순회를 더 많이 하게 되고, 값이 바뀔 때마다 연산이 되고 있다. 데이터를 추가, 수정, 삭제하는 것도 아니고 검색만 하는데 연산을 하는 것 자체가 메모리 낭비일 수 있다. 즉, 새로운 데이터가 추가될 때, 수정될 때, 삭제될 때만 연산하는 것이 더 좋다.

이럴 때 useMemo 훅을 사용한다. useMemo를 사용하면 이러한 연산 자체를 memoization할 수 있다. 그리고 특정 조건이 만족했을 때에만 다시 연산하도록 설정할 수 있다.

useMemo를 import하고, useMemo의 첫번째 매개변수로 콜백함수를 넣고 두번째 매개변수로 배열을 넣으면 된다. 이 배열은 useEffect에서 배웠던 의존성 배열이다. useEffect에서 deps에 들어가는 배열이 바뀔 때 콜백함수를 실행한다라고 배웠다. useMemo도 똑같이 deps에 포함된 값이 변경되었을 때만 콜백함수를 실행한다. 콜백함수가 반환하는 값을 useMemo도 그대로 반환을 한다.

콜백함수에는 memoization하고 싶은 연산을 넣어주면 된다. 즉 우리는 count하는 부분을 모두 콜백함수에 넣어주면 된다. 넣어준 콜백함수는 totalCount, doneCount, notDoneCount를 반환해주고 있으므로 useMemo도 똑같이 반환을 해준다. todos의 값이 변경될 때마다 연산을 실행된다.

위와 같이 useMemo를 이용해서 코드를 작성하면, 검색하는 등의 todo 데이터가 변경되지 않더라도 연산을 수행하던 방식이, 값이 변경될 때만 연산을 수행하는 코드로 바뀌었다.


React.memo - 불필요한 리렌더링 방지하기

memo?

React.memo는 component를 인수로 받아 최적화된 component로 만들어 반환한다. 최적화된 component는 props를 기준으로 memoization된다.

memoization된 component는 부모가 리렌더링되더라도 자기의 props 값이 바뀌지 않으면 리렌더링되지 않게 최적화가 된다.

실습

위 사진을 보면 체크박스를 클릭할 때마다 리렌더링되는 것들을 하이라이트해서 보여주는 것이다. 자세히 보면 Header 부분은 props로 전달되는 값도 없는데 계속해서 리렌더링되고 있다.

Header component에서 memo를 import해주고, export default memo(Header)를 해준다. 그러면 자신의 props의 값이 변하지 않을 경우에는 리렌더링 하지 않게 된다.


useCallback - 불필요한 함수 재생성 방지하기

위의 코드는 TodoItem들에서 props값이 변경된 item만 리렌더링해주는 코드인데, memo를 사용하면 props 값이 바뀌었는지 확인하는 콜백함수를 매개변수로 넣어줘야 한다. 이렇게 매번 콜백함수를 작성해서 넣어주면 번거로워질 것이다.

이럴 때 useCallback을 사용한다. import useCallback을 해주고, return문 위에서 useCallback을 사용해주면 된다. 첫번째 매개변수로는 최적화하고 싶은 함수, 즉 불필요하게 재생성되지 않도록 방지하고 싶은 함수를 넣어준다. 두번째 매개변수로는 deps를 넣어주면 된다.

이제 useCallback은 첫번째 매개변수로 전달한 콜백함수를 그대로 생성해서 반환해준다. 이 함수를 deps가 변경될 때에만 다시 생성하도록 최적화해준다. 즉 함수를 memoization해주는 것이다. deps로 빈 배열을 넣어주면, mount될 때만 함수가 생성되고, 리렌더링이 아무리 많이 되더라도 나머지 경우에는 생성하지 않게 된다.

기존의 onCreate, onUpdate, onDelete함수들을 useCallback을 통해서 리렌더링될 때 계속해서 생성되지 않게 최적화를 해준다.

이렇게 되면 작성했던 TodoItem component의 memo 메서드 안의 두번째 인자를 모두 지워줘도 onCreate, onUpdate, onDelete함수가 재생성되지 않는다.


Optimization을 언제, 어떤 것들?

최적화는 맨 마지막에 하는 것이 좋다. 항상 기능을 구현하는 것이 먼저가 되어야 하고, 기능이 완성이 되면 그 뒤에 최적화를 하는 것이 일반적인 방법이다.

모든 것들에 최적화를 하면 안되고, 꼭 필요할 것 같은 연산, 함수, component들에만 최적화를 적용하는 것이 좋다. 단순한 화면을 보여주는 component는 최적화를 진행하는 것보다 단순히 리렌더링하는 것이 더 빠를 수 있다. 사소한 component까지 모두 최적화를 진행하지는 않는다. 보통 무거운 연산이나 반복되는 연산이 있는 것들을 진행한다.



사진 및 참고 출처 - 한입 크기로 잘라먹는 리액트

profile
꾸준🐢

0개의 댓글