최초의 렌더를 줄이려면 scaffold, skeleton loader, 부분 렌더링을 해야 함
아래와 같이 "first time component rendered", 즉, 최초 렌더는 어쩔 수 없음. 이 녀석을 방지하려면 필요한 만큼한 렌더해야 함. pagination + infinite scroll, windowing 여러 기법이 있는데 필요한 걸로 사용하면 될 듯.
행동 기반 최적화
경험상 최적화를 미리할 순 없고 (kent 아저씨였는지 누구였는지, 미리 하는 useCallback, useMemo 최적화는 만악의 근원이라더라)
프로덕트가 커지고 완성 단계에서 문제가 있는 부분을 리렌더링을 방지하는 작업을 하게 된다.
이 작업을 처음 할 때 이틀 정도는 useEffect와 props, state와 싸움하면서 동작 순서를 정확히 인지하려고 했는데, 프로젝트 규모가 커지다보니까 이 과정이 불가능하다고 느껴졌다. 결론적으론 behavior 기반으로 재렌더링 작업을 하였다.
예를 들자면 다음과 같다
1. 특정 resourceCard에 단순히 호버했을 때 (리스트 전체가 렌더 되지 않게 하자)
=> 해당 Card만 렌더되도록 하자.
isCardHover state만 변경되어서 해당 카드만 재렌더링 됨을 확인함.
2; 리소스 패널과 에디터 영역을 mouse cursor가 오고갈 때 resourceCard가 재렌더링 되면 안 됨.
이제 문서 작성 영역과 library를 오고가도 리소스 카드가 재렌더링 되지 않음.
이런 식으로 "특정 동작을 하니가 여기가 특히 병목 지점이더라"를 profiler를 통해서 알아내고, 고칠 수 있다.
이렇게 내려가는 식으로 최적화를 해야지, 여기 state가 이 훅에서 쓰였으니까 여기를 이렇게 고치고... 이런 방식으로는 너무 힘들더라.
Reference를 사용하는 함수나 변수들은 어떻게 memorized를 하고, 의존성 배열을 관리해야 하나?
reference type은 그 값이 같더라도 의존성 배열에 넣으면 shallow compare를하기 때문에 넣으나 안 넣으나 재렌더링을 다시 유발한다.
애초에 아래와 같이 object의 특정 필드만 사용(당연한 primitive type 이라고 가정합니다) 한다면 아래와 같이 하는게 가장 베스트 케이스다.
const handleResourceCardClick = useCallback(
... 생략
[dispatch, folder.folderId, folder.documentId]
)
그런데 세상일이 쉽지 않은게, object나 function, array를 통짜로 쓰는 부분이 있기 마련이다.
이런 부분은 어쩔 수 없이 깊은 비교를 해야 하는데,
kent 아조씨가 만든 use-deep-compare-effect 라는 걸 사용하는 방법이 있다.
https://github.com/kentcdodds/use-deep-compare-effect
그런데 이번 프로젝트에서는 그런 부분이 많지는 않아 패키지를 굳이 설치하지는 않고, stringify해서 문자열로 치환한 후 의존성 배열에 넣어주었더니 해결되었다. 물론 매우 찜찜하지만, 이렇게 안하면 서비스를 할 수가 없는걸...
const stringifiedBacklinkIds = JSON.stringify(backlinkIds)
// eslint-disable-next-line react-hooks/exhaustive-deps
const backlinkIdsList = useMemo(() => backlinkIds, [stringifiedBacklinkIds])
이런 문제를 많은 사람들이 겪었는지, deep equal check를 해달라는 문의가 있었지만 dan 아저씨는 지원할 생각이 없다고 한다.
대신 레퍼런스를 의존성 배열로 처리하기 위한 방법을 3가지 정도 알려준다. JSON.stringify는 3번째로, 조심하라는데, 이번에는 어쩔수가 없었다.
https://github.com/facebook/react/issues/14476
다만, JSON.stringify를 사용하다보니 나름대로 몇가지 원칙이 생겼는데 별 거 없지만 아래와 같다.
1. object의 경우 {name: 'da', age: 23}과 {age: 23, name: 'da'}이 다르게 처리 되기 때문에 가급적 사용하지 않아야 한다.
2. array의 경우 적극적으로 사용해도 좋다.
그나마 위로가 되는 사실은 위버스 같이 큰 회사도 의존성 배열에 JSON.stringify를 사용한다는 것이다.
아래처럼!
'React, Next, Redux > ⚛ React.JS' 카테고리의 다른 글
runtime css-in-js is not free (0) | 2021.12.30 |
---|---|
웹 프론트엔드에서의 MVVM 디자인 패턴에 대해서 (0) | 2021.09.08 |
React에서 dnd 구현하기 (react-dnd) (0) | 2021.07.06 |
다크 모드 구현하기! with styled-components (0) | 2021.05.07 |
React에 rxjs를 곁들여 사용해보자 (0) | 2021.05.06 |