1-12. 최적화3 - 컴포넌트&함수 재사용하기 useCallback

밥이·2022년 3월 4일
0

React Project

목록 보기
12/14

삭제 버튼을 눌렀을때, 리액트 개발자 도구로 확인해보면 나머지 일기 컴포넌트들도 깜빡이면서 리렌더링이 발생하고 있다고 알려주고있고, DiaryEditor컴포넌트도 깜빡이면서 리렌더링이 되고있음.

일기를 삭제하는 과정에서 일기 리스트면 모를까 DiaryEditor컴포넌트가 깜빡일 필요는 전혀없음.

DiaryEditor 최적화 해보기

컴포넌트는 언제 렌더링이 일어날까??

  1. 본인이 가진 State에 변화가 생겼을 때
  2. 부모컴포넌트가 리렌더링 될 때
  3. 자신이 받은 prop이 변경되는 경우

이런 경우에 렌더링이 다시 일어나게됨

현재 DiaryEditor컴포넌트는 onCreate 함수하나를 받고있음. 이 함수는 저장하기를 눌렀을때 데이터의 아이템을 추가하는 역할을 하는 함수임.

onCreate함수는 App컴포넌트가 재생성 될 때 마다 계속 생성 되기 때문에, 결론적으로 이 onCreate함수가 재생성되지 않아야만 DiaryEditor컴포넌트를 React.memo()와 함께 최적화 할 수 있음

App컴포넌트의 onCreate함수로 가서 다시 생성되지 않게 해줘야함

이전에 배웠던 useMemo()가 있는데, useMemo()는 함수가 반환하는 값을 다시 사용할 수 있도록 [ ]deps Array를 기준으로 메모이제이션을 도와주는 기능이였는데, 이거는 지금 사용하면 안됨.

왜냐 useMemo()함수는 결록적으로 함수를 반환하는게 아니라 값을 반환하는거기 떄문임.
우리가 원하는건 onCreate함수를 원본 그대로 DiaryEditor컴포넌트로 보내주는거지 onCreate함수가 어떤 값을 반환하길 원하진 않음. 그래서도 안됨

그래서 지금 사용할 기능은 useCallback임

useEffect, useMemo와 똑같이 생김.

useCallback은 값을 반환하는게 아니라, 이 콜백함수를 다시 반환해주는 역할을 한다. 라고 생각하면됨

주의 할건 메모이제이션된 콜백함수를 반환함.
2번쨰 인자로 전달한 [ ]deps Array안에 들어있는 값이 변화하지 않으면 첫번째 인자로 전달한 콜백함수를 계속 재사용 할 수 있도록 도와주는 기능임

지금 우리가 원하는건 onCreate함수가 다시 재생성되지 않게 하는것임

그래서 onCreate함수에 useCallback을 적용해주고, 2번쨰 인자[ ]deps Array 에는 빈배열로 전달.

onCreate함수를 보면 어떤식으로 설계했냐면

useCallback의 첫번째 인자로 전달한 콜백함수가 이 DiaryEditor가 저장하기를 눌렀을때 데이터를 추가하는 함수가 되고,

두번째 인자로는 [ ]deps를 전달하는데 빈배열로 전달해서 Mount되는 시점에 한번만 만들고 그 다음 부터는 첫번쨰 만들었던 함수를 그대로 재사용할수 있도록 만듬.

이렇게 useCallback으로 감쌌을때 정상적으로 작동하는지 확인
useCallback을 잘 작동하면 삭제하기를 했을때 DiaryEditor컴포넌트가 리렌더가 안되는걸 볼 수 있음.

그런데!! onCreate함수에 어떤짓을 한거니까 일기저장하기를 했을때, onCreate함수가 잘 수행이 되는지 확인해보면!?

일기가 전부 없어져서 초기화 되고, 방금 작성한 1개의 일기만 나옴

그 이유는 우리가 useCallback을 활용하면서 [ ]deps Array에 아무값도 안넣어줘서 그럼

onCreate함수는 App컴포넌트가 Mount되는 시점에 한번만 생성되기 때문에 그 당시 data State의 값은 [ ] 빈배열임.

onCreate함수가 가장 마지막으로 생성됐을때 data State가 [ ]빈 배열이었기 때문에 지금 이런 현상이 발생하게 된거임

함수는 컴포넌트가 재생성 될때 다시 생성되는 이유가 있음, 왜냐면 현재의 State값을 참조할 수 있어야됨
근데 이 onCreate함수는 useCallback에 갇혀 [ ]deps를 빈배열로 전달 했기 때문에 이 onCreate함수가 알고 있는 data의 값은 그냥 [ ] 빈배열임.

그러면 어떻게 해야되느냐??

정상적으로 작동을 시키려면 [ ]deps에 data State를 넣어줘야하는데, 그런데 [ ]deps는 이 안에 있는 값이 변경되면 onCreate함수는 재생성이 됨

그러면 결론적으론 우리가 원하는 동작은 할 수 없음.. 왜 ??

지금 우리는 data State가 변화 한다고 해서 onCreate함수가 재생성 되지 않기를 바라고 있음. 근데 onCreate함수가 재생성 되지 않으면 최신의 data State의 값을 참조 할 수 없어서 이상한 동작을 하게된것

이런 상황에서는 함수형 업데이트를 사용하면됨.

함수형 업데이트란 setData 상태변화 함수에 함수를 전달하는것
상태변화 함수에 함수를 값 뿐만 아니라 함수를 전달해도됨

상태변화 함수에 함수를 전달하는걸 함수형 업데이트라고 하는데, 이렇게 인자로 data를 받아서 아이템을 추가한 데이터를 리턴하는 콜백함수를 setData함수에다가 전달할꺼임
이렇게 하면 []deps를 빈배열로 해도 항상 최신의 data State를 받은 data인자를 통해서 참조 할 수 있게 되면서 []deps를 비울 수 있도록 도와줌.
(data state의 현재값을 참조하여 onCreate함수를 재생성함)

그러고 다시 일기를 작성해 저장하면 data state의 현재값을 참조해서 정상적으로 작동하는걸 볼 수 있고, 삭제를 해도 DiaryEditor컴포넌트가 리렌더 안되는걸 볼 수 있음.

0개의 댓글