티스토리 뷰
리액트에서 컴포넌트는 JSX를 리턴하는 함수이다.
function Component(props) {
// jsx를 계산하는 과정
return JSX;
}
render 란 간단히 말해서 `브라우저에 UI를 페인트하는 것`이다.
Q. 그렇다면 리액트에서 render는 무엇일까?
- 컴포넌트를 호출하는 것
- JSX를 리턴하는 것
- JSX를 브라우저에 페인트하는 것이다.
Q. 리액트에서 re-render는 무엇일까?
- 컴포넌트 렌더링처럼 컴포넌트를 호출(call)하는 것 => 다시 함수 호출
- JSX를 리턴하는 것
- 이전 JSX와 현재 JSX를 비교해서 다른 점(difference)을 페인트하는 것
Q. re-render 발생 시점
- state가 변했을 때 => state가 setState()로 값이 변경되면 이후에 컴포넌트가 재호출된다.
- 컴포넌트가 재호출되는 시점에서 state는 최신값을 가지고 있다 그렇게 되면 state에 연관된 로직의 연산도 최신값을 기준으로 계산할 수 있다.
- 컴포넌트가 재호출 (Component re-call) => 즉, 이런 순서를 활용해서 불필요한 state를 줄이는 것이 가능하다.
👩🦰 불필요한 state를 없애는 예시 코드
// 리액트 컴포넌트 내부
const [form, setForm] = useState({
email: "",
password: "",
});
// isEmailValid는 form에 의존하고 있으므로 state로 따로 뺄 필요없고
// state가 변할때마다 컴포넌트가 재호출되기 때문에 항상 최신값을 유지할 수 있다.
const isEmailValid = form.email.includes("@");
const isDisabled = !(isValid.isEmail && isValid.isPassword);
- 외에도 useEffect(deps의 의존값)을 같이 사용하면서 불필요한 리렌더링을 트리거하지는 않는 지 유의해야 한다.
- 예시로, onChange 함수에서 form state를 setState로 변경하여 리렌더링을 일으켰는데 동시에 useEffect내부에서도 isValid 등의 값을 의존값으로 넣어놨다면 렌더링이 form의 내용이 바뀔때마다 2번씩 발생하게 되기 때문이다.
Q. 리액트에서 state를 사용하는 이유?
- UI와 상태(state)를 연동시키기 위함
- UI란 어떠한 데이터를 보기 편한 형태로 표현한 것 => 리액트는 UI와 연동되어야 하며, 변할 여지가 있는 데이터들을 state라는 형태로 사용할 수 있게 했다.
위와 같은 이유로 리액트에서 리렌더링이 발생하는 시점은 state가 변했을 때 => 특정 컴포넌트의 state가 변한다면, 해당 컴포넌트와 해당 컴포넌트의 하위에 있는 모든 컴포넌트가 리렌더링 발생
Q. 하위 컴포넌트 리렌더링 방지는 어떻게?
- state가 변한 상위 컴포넌트의 경우 당연히 UI의 변화가 있겠지만 하위 컴포넌트의 경우는 props가 변하지 않았다면 해당 컴포넌트의 UI가 변화하지 않았을 수도 있다.
- 이런 경우에는 굳이 새로운 컴포넌트 함수를 호출할 필요 없이 이전에 저장된 결과를 그대로 사용하는 것이 효율적이다. => React.memo 를 활용하자
React.memo:기존 컴포넌트의 UI를 재활용할 지 판단하는 방법
React.memo는 HOC(Higher Order Component, 고차 컴포넌트)이다.
HOC란 컴포넌트를 인자로 받아서, 컴포넌트를 리턴하는 컴포넌트이다.(Wrapper 컴포넌트같은 느낌)
function HOC(Component) {
/* do something */
return <Component />
}
- 이전 props와 다음 렌더링 때 사용될 props를 비교하여 차이가 있을 경우에만 리렌더링을 수행한다. 차이가 없다면 이전값을 재사용한다. 이를 통해 불필요한 컴포넌트 리렌더링을 방지할 수 있다.
- [props를 비교하는 방식] 기본적으로 shallow compare 하여 판단한다. shallow한 기본 비교 로직을 사용하지 않고 직접 비교하는 로직을 작성하고 싶을 경우 React.memo의 두번째 인자로 커스텀 비교 함수를 넘겨주면 된다.
- 두번째 인자로 전달된 함수는 함수의 기본 인자로 이전 props와 새로운 props가 순서대로 전달된다. 이 함수의 반환값이 true일 경우, 이전 결과를 재사용하고 false일 경우, 리렌더링을 수행한다.
function Component1(props){
const areEqual = (prevProps, nextProps) => {
//비교 로직 return true || false;
}
return JSX;
}
//두번째인자로 커스텀 비교함수 전달
export default React.memo(Component1, areEqual)
주의할 점: 상위 컴포넌트로부터 전달받은 props역시 '객체' 형태(참조형 데이터타입)로 전달받는다. 이 말은 즉, props 객체들은 매 렌더링마다 새롭게 생성된다는 소리이다. 따라서 props 객체 자체를 비교하는 것은 의미가 없다.
shallow compare을 하는 리액트는 props 객체 안의 각 property들을 Object.is(===) 연산자를 통해서 비교한다. 이 중 하나라도 false가 나온다면 props가 변경되었다고 판단하고 리렌더링을 수행한다.
자바스크립트 데이터 타입에 대해 이해하지 못한다면 memo를 잘못활용하는 상황이 발생한다.
자바스크립트는 기본적으로 비교연산자를 수행할 대 해당 데이터의 메모리 주소를 통해서 일치 여부를 판단한다.
- 원시형 타입의 경우는 데이터가 매번 새롭게 교체되면서 메모리 주소도 변경되기 때문에 비교가 쉽다.
- 참조형 타입의 경우는 내용물이 어떻게 바뀌었는지에 상관없이 해당 객체를 가리키는 메모리 주소는 동일하기 때문에 내용이 변했는지 판단하기 어렵다. 또한, 내용물이 완벽히 일치하더라도 각 객체를 가리키는 메모리 주소가 다르기때문에 두 객체가 동일하지 않다는 결과가 나온다. 내용물을 판단하려면 두 객체 안의 모든 property들을 순회하며 일일이 비교해주어야 한다. deps가 깊어질수록 연산을 수행하기 위한 복잡도는 더 늘어난다. (함수는 기본적으로 호출될 때마다 새로운 참조값을 가진다.)
- 리액트에서의 shallow compare이란 참조형 데이터 타입(객체 배열 등..)의 업데이트를 비교할 때, 내부 값의 변경 여부가 아닌 객체나 배열의 참조만을 비교하는 것을 말한다.
'Frontend > react.js' 카테고리의 다른 글
[React] React 프로젝트에 ESLint 와 Prettier, Git Hook 세팅하기 (0) | 2023.08.19 |
---|---|
[React | Vite] Vite로 구성된 React + ts 프로젝트에서 svg사용하기 (0) | 2023.08.10 |
[React | socket.io] Websockek의 개념과 리액트에서 소켓 통신하기 (0) | 2023.06.25 |
[React] Suspense 와 React.lazy (0) | 2023.05.28 |
[SWR | 서버데이터관리] SWR 사용해보기, optimistic vs pessimistic UI, cookie 공유 tip (0) | 2023.05.24 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- fs모듈 넥스트
- is()
- D 플래그
- 항해99프론트후기
- tilde caret
- 원티드 3월 프론트엔드 챌린지
- 원티드 프리온보딩 FE 챌린지
- Prittier
- 항해99프론트
- 프리온보딩 프론트엔드 챌린지 3월
- 원티드 프리온보딩 프론트엔드 챌린지 3일차
- aspect-ratio
- text input pattern
- && 셸 명령어
- getServerSideProps
- 틸드와 캐럿
- reactAPI
- 항해99추천비추천
- ~ ^
- 프리렌더링확인법
- 부트캠프항해
- getStaticPaths
- nvm경로 오류
- nvm 설치순서
- grid flex
- 타입스크립트 장점
- 타입스크립트 DT
- 원티드 FE 프리온보딩 챌린지
- float 레이아웃
- 형제 요소 선택자
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함