프로젝트 TIL (1) - [조건부렌더링 & Hooks 최적화]
오늘 한 일 😜
오늘은 내 서재 페이지에 조건에 따라 다른 UI를 보여줄 수 있는 화면을 구현했습니다.
삼항 연산자를 사용하여 조건을 분리했는데 가독성도 좋지 않은 것 같고 이러한 조건이 많아지게 된다면 렌더링 될 때에 UI가 매끄럽게 보여지지 않을 것 같다는 생각을 하게 되었습니다.
먼저 삼항연산자를 통해 작성한 코드는 다음과 같습니다.
위의 코드를 수도코드와 if/else 코드로 작성해보면 다음과 같습니다.
1. 사용자가 로그인을 한 상태이고 내 서재에 등록한 책이 있을 경우
2. 사용자가 로그인을 한 상태이고 내 서재에 등록한 책이 없는 경우
3. 사용자가 로그인을 하지 않은 상태인 경우
if(loggedUserCheck && myLibraryBookLists) {
// ...
}else if(loggedUser && !myLibraryBookLists) {
// ...
}else if(!loggedUser) {
// ...
}
내가 작성한 코드이기 때문에 나는 알아볼 수 있지만 코드는 나만 알아보기 위해 작성하는 것이 아니기 때문에 가독성을 고려하지 않을 수 없었습니다. 지금은 조건이 3가지라서 복잡해보이지는 않지만 앞으로 더 추가될지도 모르기 때문에 처음부터 가독성을 생각하고 작성하는 것이 좋다고 생각했습니다.
참고 레퍼런스
https://stackoverflow.com/questions/58137667/if-else-statement-in-react-jsx
https://stackoverflow.com/questions/53038034/conditional-rendering-for-more-for-more-then-one-condition-in-react
stackOverFlow에서 검색한 위의 자료들을 참고하여 다시 작성한 코드는 다음과 같습니다.
renderOrDetails라는 함수를 하나 선언하고 return문 안에서 렌더링 될 때에 중괄호를 사용하여 이 함수를 실행시켜 주었습니다.
구글링을 하면 이렇게 복잡한 조건부 렌더링을 따로 함수로 빼는 이유가 확장성 / 가독성 / 유지 보수성을 향상시킬 수 있어서 더 나은 방법이라고 하는데 아직까지는 크게 와닿지는 않는 것 같습니다.
더 나아가며 (함수의 최적화)
renderOrDetails 함수의 최적화를 어떻게 하면 좋을지에 대해 고민하게 되었습니다.
React가 렌더링을 실행하는 과정
- Props가 변경되었을 때
- State가 변경되었을 때
- 부모 컴포넌트가 렌더링되었을 때
- shouldComponentUpdate에서 true가 반환될 때
- forceUpdate가 실행될 때
1번과 2번의 경우 리액트는 얕은 비교를 통해 새로운 값인지 아닌지를 판단한 후 새로운 값인 경우 리렌더링을 하게 됩니다.
따라서 원시 값들은 서로 다른 참조 값을 가지고 있어도 비교함에 있어 문제가 없지만 객체, 배열, 함수와 같은 객체들은 같은 참조 값이 아니라면 새로운 값으로 판단합니다.
상위 컴포넌트의 state 변경 -> 상위 컴포넌트가 리렌더링 되면서 하위 컴포넌트에 넘겨주는 props가 새롭게 생성 -> props에 참조 타입이 있다면 동일한 값이라도 동일 참조 값이 아니므로 얕은 비교를 통해 새로운 값으로 판단하여 리렌더링을 일으킴
위와 같은 상황에서 불필요한 렌더링을 방지하기 위해 사용되는 것 중에 useCallback, React.memo 가 있습니다.
Hooks에서 최적화하기
useMemo(callback, [변경되는 값]);
- 두 번째 배열이 바뀌기 전까지 값을 기억
- 함수 컴포넌트는 매번 함수가 새로 렌더링되기 때문에 한번만 실행되면 되는 함수도 계속 호출되는 문제 발생
- 변경되는 값이 없다면 한번만 실행 후 값을 보관하는 역할로 사용가능
useRef()와 useMemo의 차이점
- useRef : Dom객체 처럼 특정한 값만 기억해야할 때
- useMemo : 함수의 return값을 기억해야 할 때
useCallback(callback, [변경되는 값]);
- 두 번째 배열이 바뀌기 전까지 함수 자체를 기억
- 함수 생성 자체가 오래걸리는 경우나 복잡한 로직의 함수에 사용하면 최적화 가능
- 변경되는 값이 없다면 state값을 맨 처음 값만 기억
- 변경되는 값이 있을 때 새로운 값을 기억할 수 있다.
- 자식 컴포넌트에 함수를 Props로 내릴 때는 useCallback을 반드시 사용 (자식 리렌더링 방지)
useMemo와 useCallback의 차이점
- useMemo : 함수의 return 값을 기억
- useCallback : 함수의 reference를 기억
위에서 알아본 최적화 방법 중에 제가 작성한 renderOrDetails 함수에서는 useMemo를 사용하는 것이 좋을 것 같다는 판단을 했습니다.
조건부 렌더링의 가독성과 확상성을 고려하여 조금 더 나은 방법을 택하기 위해 구글링을 하면서 최적화까지 신경쓸 수 있게 되어 프로젝트를 하면서 좋은 공부가 되었던 것 같습니다.
아직 다른 컴포넌트에는 최적화를 진행하지 않았는데 어느정도 UI가 완성되고 나면 시간을 내서 최적화를 적용하여 리팩토링을 꼭 해야겠습니다!!!!!!!!!
( 코드 작성하는 것 보다 최적화를 신경쓰는게 왜 더 힘들 것 같다는 느낌적인 느낌이 오는걸까.....................너무 과한 최적화는 안하는 것보다 못하다고 하니 구글링을 통해 공부를 더 한 후 적용해봐야겠다........^^)