이제 memo는 여기서
제거해도 되지만, 그래도 이 memo를 사용하는 것에 대해
더 자세히 살펴보려고 합니다
counter 컴포넌트 안에 있는 이 컴포넌트에 사용해보겠습니다
지금은 물론 이 앱에서
카운터를 증가하면
수많은 컴포넌트 함수들이
재실행되어 버립니다
더 세밀한 조정을 위해 이 아이콘 버튼들이 있고
재실행되야 하는 아이콘이 따로 있으며
CounterOutput도 있습니다
이제 CounterOutput은 타당합니다
버튼을 클릭할 때마다 output이
바뀌기 때문입니다
그러니까 이것도 다시 실행되어야 합니다
하지만 이 버튼들의 경우는 다릅니다
물론 이 button 컴포넌트와
출력값들은
따지고 보면 바뀌지 않습니다
항상 이 두 버튼이
output을 출력하는 겁니다
그러니까 이 함수들을 재-랜더링하고
재실행하는 것은 타당하지 않습니다
전에 말했듯이
이 앱에서는 큰 문제가 되지 않습니다
왜냐하면 이 함수들은 너무 적은 양의 코드를 갖고 있어서
실행하는 데 부담이 없기 때문입니다
그래도 이 icon 버튼을 메모로 감쌀 수 있습니다
불필요한 재실행을 방지하기 위함이죠
그리고 실제 랜더링되는 icon이
이 icon 버튼 안에 있기 때문에
icon 함수는 다시 실행되지 않습니다
그렇게 두 컴포넌트의 실행을 방지할 수 있는 겁니다
둘 중 하나만 memo로 감싸도 그렇습니다
그리고 물론 리액트에서 memo를
icon 버튼 함수 파일로 불러올 수 있습니다
그리고 이전과 같이 새로운 상수를 만들어
이 컴포넌트 함수를 memo로 감싸고
그걸 이런 식으로 새로 만든 상수에 내보내면 됩니다
하지만 그러면 뭔가 특이점을 하나 발견하게 됩니다
이걸 지우고 이 버튼을 눌러서 재로딩을 해봅시다
여전히 잘 실행되지만
여기서 memo가 제대로 작동하지 않은 것 같네요
혹은 작동했지만 속성 값이 바뀐 것이겠죠
하지만 그러기 위해선
icon 버튼이 받은 속성을 살펴 봅시다
이 자식 속성은 output으로 쓰였으니
결국엔 버튼의 문자인 겁니다
그러니까 버튼이 이 문자로 감싸졌고
그게 값이 자녀에게 할당된
값입니다
당연히 그 문자들은 바뀌지 않습니다
그러므로 자녀의 속성 값 또한 바뀌지 않아야 합니다
그렇다면 icon은 어떨까요?
마지막에 icon 속성은 컴포넌트에 포인터(pointer)를 받게 되고
컴포넌트 이름으로 전달 받는데 JSX 코드의 함수는 아닙니다
그냥 컴포넌트의 이름만 전달한다는 게 중요하며
그 후에 JSX 코드로 변환합니다
이 컴포넌트 함수 내에서 일어나는 일입니다
하지만 이 포인터들은
그러니까 이 함수들의 이름은 바뀌지 않는 성질을 갖고 있으며
바뀌어서는 안 됩니다
counter 컴포넌트 함수가 실행될 때 말입니다
그래서 남은 속성과 무조건 연관이 있어야 하고
여기 보이시는 이걸 그냥 button으로 전달해줬습니다
그리고 여기 다른 속성을 하나 더 설정하는데
바로 onClick을 이 함수에 지정했습니다
하지만 이게 문제라면 문제인 게
이 함수들은 바뀌지 않을 것처럼 보이지만
이들은 counter 컴포넌트 함수 내에서 생성되었다는 것을
기억하시기 바랍니다
이들은 중첩 함수입니다
그렇기 때문에 따지자면 이 counter 컴포넌트 함수가
실행될 때마다 다시 생성됩니다
그러니까 매번 이 상태가 바뀔 때
이 안에 있는 코드가 똑같고
바뀌지 않아도 괜찮습니다
컴포넌트 함수가 자바의 값과 객체로써 재생성됩니다
메모리에 있는 객체는
counter 컴포넌트 함수의 마지막 실행과는 다를 것이며
그러므로 새 속성 값이 되는 겁니다
이제 이 재생성은 막을 수 있습니다
리액트의 특별한 훅(hook)의 도움이 필요합니다
예전에 이미 효과와
useEffect 훅으로 사용했었습니다
바로 useCallback 훅입니다
이 훅은 함수의 재생성을 방지하기 위해 사용되며
또 가끔은
함수를 useEffect의 의존성으로 갖고 있을 때 필요합니다
memo를 사용할 때도 필요합니다
불필요한 재실행을 방지하기 위해서입니다
useCallback을 컴포넌트 함수 내
함수를 감싸려고 사용하기 때문입니다
그리고 useCallback으로 의존성 배열을 두 번째 인자로
전달하기 위해서도 사용됩니다
그리고 이 함수 내에 쓰일 모든
context 값들을 나열해 보겠습니다
왜냐하면 그 중 하나라도 바뀌면
새로운 함수가 생성될 것이고
가장 최신 값이 함수에 사용되기 때문입니다
하지만 여기서는 오직 setCounter만 사용합니다
상태를 업데이트하는 함수입니다
그리고 이 상태를 업데이트하는 함수들은
리액트로 인해 바뀌지 않도록 보장되어 있으며
그러므로 의존성 배열에 추가하지 않아도 됩니다
그러면 useCallback이 마지막에 값을 반환합니다
똑같은 함수지만 변하지 않도록 했습니다
그리고 이걸 변수나 상수에 저장할 수 있는데
여기 넣고 이전에 썼던 이름과 동일하게 하겠습니다
그래서 이 값들을 계속 함수로 사용할 수 있습니다
함수이기 때문입니다
하지만 이 함수들은 리액트로부터 통제를 받고
불필요하게 재생성되지 않습니다
그러니까 handleIncrement에서는
이걸 useCallback으로 감싸주겠습니다
그리고 이 의존성 배열을 설정해줍니다
그게 다 끝나면 전체 저장을 하고
재로딩을 하고 이것도 지워주면, 보이듯이
'증가하기'를 클릭해도 icon 버튼들과
중첩 icon 컴포넌트들이 재실행되지 않으며
대신 이제 counter ouput만 출력됩니다
타당한 결과입니다
바뀐 게 있어도 업데이트를 할 필요는 없기 때문입니다