일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 개발일지
- 특성선택자
- 부트캠프 #CSS #개발일지 #TIL #박스모델
- 부트캠프 #개발일지 #TIL #Position #위치
- 부트캠프 #스파르타코딩클럽 #개발일지# #html
- 부트캠프 #개발일지 #TIL #CSS속성 #float #clear
- 템플릿스트링
- 부트캠프 #개발일지 #TIL #그리드 #CSS
- appendChild
- 알고리즘
- 부트캠프 #코딩 #개발일지 #프론트엔드 #CSS #TIL
- CSS
- ㅜㄹㄹ
- 부트캠프 #CSS #개발일지 #TIL
- 깃허브오류
- 개발일지 #TIL #프론트엔드 #HTML
- 부트캠프 #스파르타코딩클럽 #개발일지# #TIL #Javascript #confirm #location.href
- textContent
- 부트캠프 #개발일지 #TIL #FlexboxFroggy #displayflex #flexbox
- useState
- Til
- useEffect
- 부트캠프
- querySelector
- js
- 결합선택자
- React
- 리액트
- JS예제
- 의사클래스
- Today
- Total
나의 개발일지
[React] react-memo / useMemo / useCallback 복습하기 본문
react-memo
- memo(React.memo) : 컴포넌트를 캐싱
부모 컴포넌트가 리렌더링 되면 자식 컴포넌트는 모두 리렌더링 되는데
자식 컴포넌트는 바뀐 것이 없는데 리렌더링이 된다면 너무 비효율적임
이러한 문제점을 돕는 게 바로 memo다
src > App.jsx
import { useState } from "react";
import Box1 from "./components/Box1";
import Box2 from "./components/Box2";
import Box3 from "./components/Box3";
function App() {
console.log("App 컴포넌트가 렌더링되었습니다");
const [count, setCount] = useState(0);
const onPlusButton = () => [setCount(count + 1)];
const onMinusButton = () => [setCount(count - 1)];
return (
<>
<h2>카운트 예제입니다!</h2>
<p>현재 카운트 : {count}</p>
<button onClick={onPlusButton}>+</button>
<button onClick={onMinusButton}>-</button>
<div style={{ display: "flex", marginTop: "10px;" }}>
<Box1 />
<Box2 />
<Box3 />
</div>
</>
);
}
export default App;
App컴포넌트의 카운트 함수를 실행했는데 자식으로 있는 Boxes도 렌더링이 되었다
이를 위해 Boxes에 React.memo(Box(n)) 을 사용하면 된다!
src > components > Box1
import React from "react";
const style = {
width: "100px",
height: "100px",
backgroundColor: "pink",
color: "white",
};
function Box1() {
console.log("Box1 컴포넌트가 렌더링되었습니다");
return <div style={style}>Box1</div>;
}
export default React.memo(Box1);
src > components > Box2
import React from "react";
const style = {
width: "100px",
height: "100px",
backgroundColor: "lightgreen",
color: "white",
};
function Box2() {
console.log("Box2 컴포넌트가 렌더링되었습니다");
return <div style={style}>Box2</div>;
}
export default React.memo(Box2);
src > components > Box3
import React from "react";
const style = {
width: "100px",
height: "100px",
backgroundColor: "lightblue",
color: "white",
};
function Box3() {
console.log("Box3 컴포넌트가 렌더링되었습니다");
return <div style={style}>Box3</div>;
}
export default React.memo(Box3);
처음에만 렌더링이 되고 이후엔 렌더링이 되지 않음을 확인할 수 있다
useMemo
: memo --> memoization (기억하다)
특별한 곳에 메모리를 저장한다
이미 저장된 값을 단순히 꺼내와서 쓴다 (캐싱한다)
import React, { useState } from "react";
function App() {
const [number, setNumber] = useState(0);
const [isKorea, setIsKorea] = useState(true);
const location = isKorea ? "한국" : "외국";
return (
<div>
<h2>하루에 몇 끼 먹어요?</h2>
<input
type="number"
value={number}
onChange={(e) => {
setNumber(e.target.value);
}}
/>
<hr />
<h2>어느 나라에 있어요?</h2>
<p>나라 : {location}</p>
<button
onClick={() => {
setIsKorea(!isKorea);
}}
>
비행기 타자
</button>
</div>
);
}
export default App;
type이 number로 된 input창과 비행기 타자라는 버튼을 누르면 외국 또는 한국으로 바뀌는 토글 버튼이 있다
여기서 인풋창을 조작할 때는 비행기 타자 버튼이 같이 리렌더링 되지 않게 하기 위해서
useEffect를 쓴다
useEffect(() => {
console.log("useEffect 호출");
}, [location]);
location이 변경될 때만 리렌더링이 된다.
하지만 만약,
const location = isKorea ? "한국" : "외국";
이 부분이 객체라면 상황은 완전 달라진다
const location = {
country: isKorea ? "한국" : "외국",
};
input창의 값이 변경됨에 따라 useEffect도 실행되었다
그 이유는
원시데이터 타입과 객체 타입의 메모리 저장 방식이 다르기 때문이다
원시데이터는 변수에 데이터가 바로 들어가지만 객체는 크키가 크기 때문에
메모리 상의 공간에 할당이 되고 그 메모리 주소가 변수에 할당이 되는 것이다
원시타입은 같은 데이터 값을 바라보고 있기 때문에 두 변수가 일치하지만
객체타입은 변수가 메모리 상의 주소로 저장이 되고 그 메모리 주소는 각각 다르므로 일치하지 않는다
그래서 location의 객체도 같은 데이터 같지만 사실상 다른 값이므로
useEffect는 location이 참조하고 있는 주소가 바꼈다고 생각하여 리렌더링이 되는 것이다
이때 useMemo를 사용하여 location의 데이터를 저장하는 것이다
useMemo(( )=>{ } , [ ])
첫 번째 인자는 콜백함수, 두 번째 인자는 의존성 배열을 갖는다.
const location = useMemo(() => {
// 객체 타입
return { country: isKorea ? "한국" : "외국" };
}, [isKorea]);
이제 바뀌지 않는 것을 확인할 수 있다!
참고한 영상
https://www.youtube.com/watch?v=e-CnI8Q5RY4&list=PLZ5oZ2KmQEYjwhSxjB_74PoU6pmFzgVMO&index=6
useCallback
import React, { useState } from "react";
function App() {
const [number, setNumber] = useState(0);
const someFunction = () => {
console.log(`someFunction: number: ${number}`);
return;
};
return (
<div>
<input
type="number"
value={number}
onChange={(e) => {
setNumber(e.target.value);
}}
/>
<br />
<button onClick={someFunction}>Call someFunc</button>
</div>
);
}
export default App;
input창에 입력된 숫자만큼 call someFunc 버튼을 누르면 콘솔창에 값이 찍히는 코드이다
useEffect(() => {
console.log("someFunction이 변경되었습니다.");
}, [someFunction]);
someFunction에 useEffect를 주었는데도 input의 값을 변경했더니 콘솔창에 찍히는 걸 확인할 수 있다
즉, 리렌더링이 계속 되고 있다
왜 그런걸까?
우리는 함수형 컴포넌트를 사용하고 있고, app이라는 함수가 호출될 때마다 정의돼있는 변수가 다시 초기화된다
someFunction도 함수객체를 담은 변수이기 때문에 초기화가 되어 리렌더링이 되는 것이다
또한 함수객체는 크기가 크기 때문에 변수에 바로 저장되는 것이 아니고 메모리 공간에 담기기 때문에 다른 데이터로 인식하여 우리가 원하는 결과가 나오지 않는 것이다
useCallback 사용하기
const someFunction = useCallback(() => {
console.log(`someFunction: number: ${number}`);
return;
}, []);
someFunction을 메모이제이션하여 저장한다 ( 재사용을 한다 )
더 이상 리렌더링되지 않는다.
하지만 또 하나의 문제점은 숫자를 변경하고 버튼을 눌렀을 때
콘솔창에 0이라고 출력이 된다
그 이유는 메모이제이션을 했을 때, number의 값이 0이었기 때문!!!
const someFunction = useCallback(() => {
console.log(`someFunction: number: ${number}`);
return;
}, [number]);
의존성 배열에 number를 넣어주어서 number의 값이 바뀔 때마다
리렌더링이 되는 것을 확인할 수 있다.
참고한 영상
https://www.youtube.com/watch?v=XfUF9qLa3mU
'React > 복습' 카테고리의 다른 글
[React] useContext 복습하기 (0) | 2023.12.21 |
---|---|
[React] 리액트 복습하기 (Props) (0) | 2023.11.04 |