"Rendered more hooks than during the previous render"
살며 처음 본 에러다. 대충 hook을 잘못 썼다는 거긴한데.
stackoverflow 검색 결과 같은 문제를 겪은 사람들이 받은 답변들은 아래와 같다.
1. Move all hooks to the top level of the function component
2. Avoid using hooks within conditions to fix the problem.
막막하다. 코드에 hook이 적힌 곳이 너무도 많다.
문제가 발생한 곳의 커밋을 확인하기위해 무자비하게 커밋을해논 곳을 확인했고 여러번 checkout한 결과
아래 그림처럼 드래그한 부분을 기점으로 문제 발생함을 확인.
(이번을 계기로 저런 무식한 커밋들은 하면 안된다는것을 깨달음. 보자마자 '헉'하게됨.
git reset을 잘 활용하자
물론 의미있는 수행단위의 커밋은 필요함. 만약 모든 수행을 하나의 커밋으로 몰아 넣었더라면 이번 이슈해결이 더 오래걸렸을 것이다.)
6c9c623, b400221 사이를 기점으로 문제 확인.
차차 해결과정이 잡혀나가는 느낌.
저 둘 사이의 코드 차이를 어떻게 봐야하는지를 여기저기 자문을 구하다보니 아래와 같은 CLI로 찾을 수 있었다.
git diff 6c9c623 b400221 > my.patch
git apply my.patch
2개의 커밋간의 차이를 보는 방법 링크
수많은 파일들과 코드에서 4개의 파일로 좁혀졌고(훅에 의해 발생됐다라는 전제를 가지고 있었기 때문에 여기서부턴 가벼운 노가다라 관련부분을 지워보고렌더링, 지워보고 렌더링)
위의 과정 끝에 아래의 파일의 코드에 의해 에러발생 확인.
components/features/common/custom-fields/story-card.js
const browserSize = useBrowserSize();
위의 코드는 반응형 구분을 줄 때 사용하는 코드이다. 위에 적어 놓은 이슈 에러 문구 통해 해결방법데로라면,
1. '모든 훅들을 함수형 컴포넌트 최상단에다 올려라.
2. 조건문 안에 훅을 쓰지마라.
훅을 위에도 올려보고 조건문을 찾아보려해도 너무 복잡하고 해결이 안된다.
보다보니 문득 'storycard에서 왜 분기처리를 했지?' 조선닷컴의 가장 중요한 심장과도 같은 storycard에 부하를 주는 행위를 하고 있었다.(if문 분기처리를 Headline 컴포넌트에서 해도 되는것을 storycard 컴포넌트에서 하고 있었음)
Headline컴포넌트를 보니 이미 과거의 다른 개발자가 다른 방법으로 반응형을 그곳에서 사용하고 있었고 그것을 그대로 이용해서 반응형을 썼으면 됐었던 것이다.
조선닷컴 코드에서 반응형을 사용하는 방법이 아래와 같이 3가지 방식이 있다.
import { isMobileBP } from '../../../../utilities';
const [isMobile, checkMobile] = useState(isMobileBP());
useEffect(() => {
window.addEventListener('resize', () => {
checkMobile(isMobileBP());
});
});
if (isMobile) {
blabla~~~~~~~~~~~~
}
if (!isMobile) {
blabla~~~~~~~~~~~~
}
import { useBrowserSize } from '~/utilities/browser-size';
const browserSize = useBrowserSize(true);
if (browserSize === ‘lg') {
blabla~~~~~~~
}
if (browserSize === ‘md') {
blabla~~~~~~~
}
if (browserSize === ’sm') {
blabla~~~~~~~
}
import { browserSizes } from '~/utilities/browser-size';
if (size === browserSizes.SMALL) {
blabla~~~~~~~
}
if (size === browserSizes.MEDIUM) {
blabla~~~~~~~
}
if (size === browserSizes.LARGE) {if (size === browserSizes.SMALL) {
blabla~~~~~~~
}
리액트를 사용하는 이유 중 하나인 컴포넌트의 분리에 대한 고려를 했어야 했다.
story-card.js에 있을 필요없는 hook 및 함수를 아래 파일 headline.js에 옮기니 해결됨
Headline컴포넌트에 반응형 2번째 방법을 과거의 개발자가 사용하고 있었으니 그대로 사용.
/Users/chosunbiz/Chosun-PageBuilder-Fusion-Features/components/features/common/custom-fields/story-card.js
/Users/chosunbiz/Chosun-PageBuilder-Fusion-Features/components/features/story-card/_children/headline.jsx