2023. 4. 18. 13:53ㆍ개발공부 기강잡자/React | JavaScript | NodeJS
<Udemy 리액트 챌린지 3주차>
이정환 강사님의 강의 '한입 크기로 잘라먹는 리액트'를 수강하고 있습니다.
Udemy에서 진행하고 있는 리액트 챌린지에 참여하며 3주차 미션으로 "섹션 6 React 기본 - 일기장 만들어보기"을 수강한 내용을 정리합니다. 👍
컴포넌트 재사용
> State의 변화로 부모 컴포넌트가 리렌더링 될 때, 해당 State를 사용하지 않는 컴포넌트는 리렌더링 하지 않게 하기
부모 컴포넌트에서 {count, text}
두가지의 State를 관리하고 있을 때, State에 변화가 생기면 부모 컴포넌트가 리렌더되고, 자식 컴포넌트들도 리렌더된다.
그런데, {text}
State만 사용하는 컴포넌트의 경우 {count}
State가 변화할 때도 불필요한 리렌더가 발생하게 된다.
👉 불필요한 렌더링을 막기 위해서 컴포넌트에 업데이트 조건을 걸면 된다.
{text}
State가 변화할 때만 렌더링 하도록 업데이트 조건을 걸면, {count}
State가 변경될 땐 렌더링 하지 않는다.
연산의 낭비를 막아서 성능을 향상시킬 수 있다!💡
React.memo
: 함수형 컴포넌트에게 업데이트 조건을 거는 법
https://ko.reactjs.org/docs/react-api.html#reactmemo
React.memo 는 고차 컴포넌트이다.
동일한 props로 동일한 결과를 렌더링해낸다면, 컴포넌트를 렌더링하지 않고 마지막으로 렌더링된 결과를 재사용
props 변화에만 영향을 받는다.
고차 컴포넌트 : 고차 컴포넌트는 컴포넌트를 가져와 새 컴포넌트를 반환하는 함수
https://ko.reactjs.org/docs/higher-order-components.html
const MyComponent = React.memo(function MyComponent(props) {
/* props를 사용하여 렌더링 */
});
👉 함수형 컴포넌트를 React.memo의 인자로 넘겨주면, 상수 MyComponent
로 새 컴포넌트 함수를 반환한다.
✔️ 똑같은 props를 전달받으면 리렌더링을 하지 않는 컴포넌트를 만들어준다.
(물론, 자기 자신이 갖고 있는 State가 바뀌면 리렌더링 된다. 부모 컴포넌트에 의한 리렌더를 막는 것임)
예제1
: State로 {count, text}
를 사용하는 부모 컴포넌트 OptimizeText
t와 자식 컴포넌트 TextView, CountView
import React, { useState, useEffect } from "react";
const TextView = ({ text }) => {
useEffect(() => {
console.log(`Update :: Text : ${text}`);
});
return <div>{text}</div>;
};
const CountView = ({ count }) => {
useEffect(() => {
console.log(`Update :: Count : ${count}`);
});
return <div>{count}</div>;
};
const OptimizeText = () => {
const [count, setCount] = useState(1);
const [text, setText] = useState("");
return (
<div style={{ padding: 50 }}>
<div>
<h2>count</h2>
<CountView count={count} />
<button onClick={() => setCount(count + 1)}>+</button>
</div>
<div>
<h2>text</h2>
<TextView text={text} />
<input value={text} onChange={(e) => setText(e.target.value)} />
</div>
</div>
);
};
export default OptimizeText;
결과 화면
+ 버튼을 눌렀을 때 > Count
값만 변화하지만 TextView
컴포넌트도 리렌더링 되고 있음
👉 낭비가 발생한다!
React.memo를 사용하여 TextView
를 수정하면 낭비를 해결할 수 있다.👇
const TextView = React.memo(({ text }) => {
useEffect(() => {
console.log(`Update :: Text : ${text}`);
});
return <div>{text}</div>;
});
: prop인 text
가 바뀔 때가 아니면 렌더링이 발생하지 않는다!
예제2
: props로 count
를 받는 컴포넌트 CounterA
와 props로 객체 obj
를 받는 CounterB
예제
import React, { useState, useEffect } from "react";
const CounterA = React.memo(({ count }) => {
useEffect(() => {
console.log(`Update :: Count A : ${count}`);
});
return <div>{count}</div>;
});
const CounterB = React.memo(({ obj }) => {
useEffect(() => {
console.log(`Update :: Count B : ${obj.count}`);
});
return <div>{obj.count}</div>;
});
const OptimizeText = () => {
const [count, setCount] = useState(1);
const [obj, setObj] = useState({
count: 1,
});
return (
<div style={{ padding: 50 }}>
<div>
<h2>Counter A</h2>
<CounterA count={count} />
<button onClick={() => setCount(count)}>A Button</button>
</div>
<div>
<h2>Counter B</h2>
<CounterB obj={obj} />
<button onClick={() => setObj({ count: obj.count })}>B Button</button>
</div>
</div>
);
};
export default OptimizeText;
결과
buttonA
를 눌러도 count
의 값이 변하지 않았으므로 console에 Update가 출력되지 않음
buttonB
를 눌러도 객체 obj
의 count
의 값이 변하지 않으므로 console에 Update가 출력되지 않아야하는데, 얕은 비교로 인해 컴포넌트의 리렌더링이 일어남
얕은 비교
: 객체의 주소에 의한 비교
👉 객체가 가지는 값이 같더라도 객체의 주소가 다르기 때문에 다르다고 판단
setObj({ count: obj.count })
→ count값이 같은 새로운 객체를 생성해서 상태값 obj에 할당하므로 객체의 주소가 바뀐다.
비교함수 areEqual
: React.memo의 두번째 인자로 비교 함수를 전달하면 얕은 비교를 하지 않도록 할 수 있다.
const areEqual = (prevProps, nextProps) => {
if (prevProps.obj.count === nextProps.obj.count) {
// nextProps가 prevProps와 동일한 값 -> 리렌더 X
return true;
}
return false; // 다른값->리렌더
};
const CounterB = React.memo(({ obj }) => {
useEffect(() => {
console.log(`Update :: Count B : ${obj.count}`);
});
return <div>{obj.count}</div>;
}, areEqual); // 비교함수 전달
React.memo
에 areEqual
비교 함수를 정의해서 전달할 수 있다.
const CounterB = React.memo(({ obj }) => {
useEffect(() => {
console.log(`Update :: Count B : ${obj.count}`);
});
return <div>{obj.count}</div>;
}, areEqual); // 비교함수 전달
const areEqual = (prevProps, nextProps) => {
if (prevProps.obj.count === nextProps.obj.count) {
// nextProps가 prevProps와 동일한 값 -> 리렌더 X
return true;
}
return false; // 다른값->리렌더
};
: 객체의 값이 동일한지 ===
연산자를 사용해서 확인하는 areEqual
함수를 정의해서 전달했다.
빨리 강의 진도 나가서 일기장 업그레이드하고 싶은데 취준 때문에 바빠서 하루에 하나만 겨우 듣고 있다. ㅠㅠ
그래도 기초적인 부분 놓치지 않도록 공부하고 있고,, 느리더라도 절대 완강에 실패하지 않을 것이다...
챌린지는 이번주가 마지막이라... 챌린지 기한 내에 나만의 일기장 만들어보기 까지는 못할 것 같다.🥲
출처 : Udemy '한입 크기로 잘라먹는 리액트' (이정환)
'개발공부 기강잡자 > React | JavaScript | NodeJS' 카테고리의 다른 글
[React] 최적화 : useCallback (0) | 2023.04.24 |
---|---|
[React] Memoization - 연산결과 재사용 : UseMemo (1) | 2023.04.17 |
[React] API 호출하고 바인딩하기/React developer tools 소개 (0) | 2023.04.17 |
[React] React의 LifeCycle (0) | 2023.04.16 |
[React] React 기본 : 리스트 렌더링/아이템 추가, 삭제, 수정 (0) | 2023.04.15 |