티스토리 뷰
React.memo는 함수형 컴포넌트를 최적화할 수 있다. (클래스형에는 적용되지 않음)
사용방법은 아래와 같이 해당 컴포넌트를 react.memo로 wrap해주면 된다.
import React from 'react';
import MyParagraph from "./MyParagraph';
const DemoOutput = (props) => {
console.log('demooutput Running');
return <MyParagraph>{props.show ? "this is new!" : ""}</MyParagraph>
};
export default React.memo(DemoOutput); //리액트 메모를 원하는 해당 컴포넌트에 wrap한다.
😎memo의 역할은 무엇인가요?
- React.memo는 인자로 들어간 컴포넌트에 어떤 props가 입력되는지 확인하고 입력되는 모든 props의 신규 값을 확인한 뒤 이를 기존의 props의 값과 비교하도록 리액트에게 전달한다. 그리고 props의 값이 바뀐 경우에만 컴포넌트를 재실행 및 재평가하게 된다. 즉, 부모 컴포넌트가 변경되었지만 인자로 들어간 컴포넌트의 props값이 바뀌지 않는다면 해당 컴포넌트의 실행은 건너뛰게 된다.(그렇게 되면 해당 컴포넌트의 자식 컴포넌트도 렌더링되지 않겠죠?) -> 불필요한 재렌더링을 피할 수 있다! 최적화가 이루어지고 있다.
✅그렇다면 이 hook을 모든 컴포넌트에 적용하면 좋은게 아닌가요? 왜 모든 컴포넌트에 적용하지 않는걸까요?
- 최적화에는 대가가 따르기 때문이다.
- memo메소드는 App에 변경이 발생할 때마다 해당 컴포넌트로 와서 이전 props값과 현재 props값을 비교하게 하는데 그렇기 때문에 리액트가 두 가지 작업을 할 수 있어야 한다. 우선 이전 props값을 저장할 공간이 필요하고 두 값을 비교하는 작업이 필요하다. 그렇기 때문에 해당 프로젝트가 크거나 프로젝트가 커서 트리의 상위쪽에 존재하는 컴포넌트(자식 컴포가 많은 경우)가 아니라면 굳이 memo를 추가하는 작업이 필요하지 않게 된다.
✅하드코딩된 값(고정값)을 props로 내려주는 컴포넌트에 memo를 적용하면 재렌더링이 되지 않겠네요?
- React.memo는 props를 통한 객체나 배열 또는 함수(참조형)를 가져오는 컴포넌트에 적용했을 때 유감스럽게도 재렌더링이 됩니다.
- 그 이유는 자바스크립트가 참조형 값에 대해서는 형태가 같더라도 다른 값이라고 인식하기 때문입니다.
- e.g.) let obj1 = {}, let obj2 = {} , obj1 === obj2 // false 그렇기 때문에 memo는 값이 변경되었다고 인식하여 재렌더링을 합니다.
✅ React.memo는 props를 통한 객체나 배열 함수를 가져오는 컴포넌트에는 사용할 수 없나요?
- 다른 훅을 사용하면 memo를 원하는 방식대로 사용할 수 있다.
- 해결방법: 객체를 생성하고 저장하는 방식만 변경해주면 된다. -> 추가적인 리액트 훅이 필요하다. useCallback Hook을 사용하면 된다.
😎useCallback이란?
- 컴포넌트 실행 전반에 걸쳐 함수를 저장할 수 있게 하는 훅으로 리액트에게 우리는 이 함수를 저장할 것이고 매번 실행할 때마다 이 함수를 재생성할 필요가 없다는 것을 알릴 수 있다. 이렇게되면 동일한 함수 객체가 메모리의 동일한 위치에 저장되므로 이를 통한 비교 작업을 할 수 있다.
let obj1 = {};
let obj2 = {};
obj1 === obj2; // false
obj2 = obj1; //같은 공간을 가리키도록 할당
obj1 === obj2; //true
라는 위의 예시에서 obj2 === obj1 라는 작업을 통해 같은 메모리 안의 같은 위치를 가리키게 한다면 obj1 ===obj2 // true로 두 객체는 같은 객체로 간주한다. 이것이 바로 useCallback이 하는 일이다.
우리가 선택한 함수를 리액트의 내부 저장 공간에 저장해서 함수 객체가 실행될 때마다 이를 재사용할 수 있도록 한다.
useCallback의 사용방법은 memo와 같이 쉽다. 저장하려는 함수를 래핑하면 된다.
toggleParagraphHandler 라는 함수를 wrapping하고 싶다면 아래와 같이해주면된다.
const toggleParagraphHandler = useCallback(()=>{
setShowPharagraph((prevShowParagraph)=>!prevShowParagraph);
}, []);
- useCallback함수는 첫번째 인자로 래핑하려는 함수를 첫번째 인자로 전달하면 이 저장된 함수를 반환해준다. 그리고 이 App함수가 다시 실행되면 useCallback이 리액트가 저장한 함수를 찾아서 그 같은 함수 객체를 재사용한다. 따라서 어떤 함수가 절대 변하면 안된다면 useCallback을 사용하여 함수를 저장하면 된다.
- useCallback은 두번째 인자로 useEffect처럼 의존성 배열을 전달하는데 이 배열은 무조건 있어야 하고 useCallback으로 감싼 컴포넌트로부터 어떤 값을 넣어도 사용 가능하다. 예를 들어 state나 props 컨텍스트를 지정할 수 있다. 그렇지만 굳이 의존성 배열에 값을 넣어주지 않아도 된다.
(사실 이해가 잘 안가서 우선은 빈배열인 상태여도 오케이라고 이해함;)
✅그렇다면 useCallback의 의존성 배열에는 뭘 넣어야 하는지..?
- 내 함수는 모든 재렌더링 주기마다 항상 똑같은 로직을 쓰는데 의존성 배열은 왜 필요함..?이라는 의문에 대한 해답
- 해당 질문에 대해서는 클로저에 대한 개념이 필요하다. (전에 배웠을 때도 어려웠는데 지금은 더 모르겠음..)
- 해당 질문에 대한 대답은 강의를 다시 보고 정리하겠습니다.
- https://ko.javascript.info/closure
'Frontend > react.js' 카테고리의 다른 글
[React | hooks] useRef & useEffect(with. debouncing) (0) | 2022.09.06 |
---|---|
[React | SEO] 리액트에서 SEO하기 (0) | 2022.08.16 |
[Redux toolkit] #1 리덕스 툴킷 정리 (0) | 2022.06.30 |
[React JS] 리액트 state관리 방법 (0) | 2022.05.26 |
[React | node.js] Node.js프로젝트 세팅 (0) | 2022.05.18 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- Prittier
- aspect-ratio
- 프리온보딩 프론트엔드 챌린지 3월
- 프리렌더링확인법
- is()
- fs모듈 넥스트
- 부트캠프항해
- ~ ^
- 항해99추천비추천
- 원티드 FE 프리온보딩 챌린지
- && 셸 명령어
- 항해99프론트후기
- getStaticPaths
- 원티드 프리온보딩 프론트엔드 챌린지 3일차
- 타입스크립트 DT
- nvm경로 오류
- D 플래그
- 형제 요소 선택자
- nvm 설치순서
- grid flex
- tilde caret
- float 레이아웃
- getServerSideProps
- 틸드와 캐럿
- 원티드 3월 프론트엔드 챌린지
- 원티드 프리온보딩 FE 챌린지
- reactAPI
- 항해99프론트
- 타입스크립트 장점
- text input pattern
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함