대표적인 최적화 React-Hooks
리-렌더링의 발생 조건
- 컴포넌트에서 state가 바뀌었을 때
- 컴포넌트가 내려받은 props가 변경되었을 때
- 부모 컴포넌트가 리-렌더링 된 경우 자식 컴포넌트는 모두
리액트에서 불필요한 렌더링이 발생하지 않도록 최적화하는 대표적인 방법
- memo(React.memo) : 컴포넌트를 메모이제이션(memoization)
- useCallback : 함수를 메모이제이션(memoization)
- useMemo : 함수가 리턴하는 값을 메모이제이션(memoization)
•React.memo
부모가 리렌더링 되면 자식은 모두 리렌더링 됩니다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
//App.jsx
import React, { useState } from "react";
import Box1 from "./components/Box1";
import Box2 from "./components/Box2";
const boxesStyle = {
display: "flex",
marginTop: "10px",
};
function App() {
console.log("App 컴포넌트가 렌더링되었습니다!");
const [count, setCount] = useState(0);
// 1을 증가시키는 함수
const onPlusButtonClickHandler = () => {
setCount(count + 1);
};
// 1을 감소시키는 함수
const onMinusButtonClickHandler = () => {
setCount(count - 1);
};
return (
<>
<h3>카운트 예제입니다!</h3>
<p>현재 카운트 : {count}</p>
<button onClick={onPlusButtonClickHandler}>+</button>
<button onClick={onMinusButtonClickHandler}>-</button>
<div style={boxesStyle}>
<Box1 />
<Box2 />
</div>
</>
);
}
export default App;
//Box1.jsx
import React from "react";
const boxStyle = {
width: "100px",
height: "100px",
backgroundColor: "#91c49f",
color: "white",
// 가운데 정렬 3종세트
display: "flex",
justifyContent: "center",
alignItems: "center",
};
function Box1() {
console.log("Box1이 렌더링되었습니다.");
return <div style={boxStyle}>Box1</div>;
}
export default Box1;
//Box2 동일
|
cs |
App.jsx의 버튼을 누르면 자식인 Box1,2까지 전부 리렌더링 되는데
이것을 memo를 통해 해결할 수 있습니다.
1
2
|
export default React.memo(Box1);
export default React.memo(Box2);
|
cs |
이렇게 React.memo를 컴포넌트 전체를 감싸주면 컴포넌트를 메모이제이션(memoization)할 수 있습니다.
•useCallback
React.memo는 컴포넌트를 메모이제이션 했다면,
useCallback은 인자로 들어오는 함수 자체를 메모이제이션(memoization) 합니다.
아래의 코드는 React.memo를 한 코드에 초기화 함수를 추가해 주었습니다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
//App.jsx
function App() {
console.log("App 컴포넌트가 렌더링되었습니다!");
const [count, setCount] = useState(0);
// 1을 증가시키는 함수
const onPlusButtonClickHandler = () => {
setCount(count + 1);
};
// 1을 감소시키는 함수
const onMinusButtonClickHandler = () => {
setCount(count - 1);
};
//카운트 초기화 함수 추가
const initCount = ( ) => {
setCount(0);
};
return (
<>
<h3>카운트 예제입니다!</h3>
<p>현재 카운트 : {count}</p>
<button onClick={onPlusButtonClickHandler}>+</button>
<button onClick={onMinusButtonClickHandler}>-</button>
<div style={boxesStyle}>
<Box1 initCount={initCount}/> //props로 함수를 내려줌
<Box2 />
</div>
</>
);
}
//Box1.jsx
...
function Box1({ initCount }) {
console.log("Box1이 렌더링되었습니다.");
return (
<div style={boxStyle}>
<button onClick={()=>{initCount()}}>초기화</button>
</div>
);
}
...
|
cs |
이렇게 하면 App, Box1 둘다 리렌더링 됩니다.
React.memo를 통해 메모이제이션을 했는데 리렌더링이 되는 이유❔
✔함수형 컴포넌트를 사용하기 때문에 App.jsx가 리렌더링 되면서 코드가 다시 만들어지기 때문입니다.
1
2
3
4
|
//카운트 초기화 함수 추가 << App.jsx에 있는 요녀석
const initCount = ( ) => {
setCount(0);
};
|
cs |
이것을 useCallback을 이용해 해결할 수 있습니다.
1
2
3
4
5
|
const initCount = useCallback(() => {
setCount(0);
}, [ ]);
//useCallback을 쓰고 마지막에 의존성배열 [ ]을 추가하여 props를 보내도 변하지 않게 해준다.
|
cs |
•useMemo
useMemo는 함수가 리턴하는 값을 메모이제이션(memoization)하는 것으로
1
2
3
4
5
6
7
|
// as-is
const value = 반환할_함수();
// to-be
const value = useMemo(()=> {
return 반환할_함수()
}, [dependencyArray]);
|
cs |
dependency Array의 값이 변경 될 때만 반환할 함수( )가 호출되고
그 외의 경우에는 memoization 해놨던 값을 가져오기만 합니다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
//App.jsx
import "./App.css";
import HeavyComponent from "./components/HeavyComponent";
function App() {
const navStyleObj = {
backgroundColor: "yellow",
marginBottom: "30px",
};
const footerStyleObj = {
backgroundColor: "green",
marginTop: "30px",
};
return (
<>
<nav style={navStyleObj}>네비게이션 바</nav>
<HeavyComponent />
<footer style={footerStyleObj}>푸터 영역이에요</footer>
</>
);
}
export default App;
//components>HeavyComponent.jsx
import React, { useState, useMemo } from "react";
function HeavyButton() {
const [count, setCount] = useState(0);
const heavyWork = () => {
for (let i = 0; i < 1000000000; i++) {}
return 100;
};
// CASE 1 : useMemo를 사용하지 않았을 때
const value = heavyWork();
// CASE 2 : useMemo를 사용했을 때
// const value = useMemo(() => heavyWork(), []);
return (
<>
<p>나는 {value}을 가져오는 엄청 무거운 작업을 하는 컴포넌트야!</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
누르면 아래 count가 올라가요!
</button>
<br />
{count}
</>
);
}
export default HeavyButton;
|
cs |
HeavyComponent 안에서는 const value = heavyWork() 를 통해서 value값을 세팅해주고 있고
다른 state(카운트)가 바뀔 때 마다 계속해서 호출되는데 useMemo( )로 감싸주게 되면 처음 리턴한 값을 저장하기 때문에 state가 바뀌어도 변경되지 않습니다.
1
2
3
4
5
|
// CASE 1 : useMemo를 사용하지 않았을 때
const value = heavyWork();
// CASE 2 : useMemo를 사용했을 때
const value = useMemo(() => heavyWork(), []);
|
cs |
'코딩이야기 > React 공부' 카테고리의 다른 글
[React] React-Hooks 간단 정리 (1) (0) | 2024.07.03 |
---|---|
[React] React에서 SVG 쓰는 방법 (0) | 2023.10.31 |
[React기초] 리액트 Routing & SPA & CSR (0) | 2023.06.21 |
[React 기초] JSX와 바벨(babel)은 무엇인가? (0) | 2023.04.19 |
[React기초] - State (0) | 2023.04.19 |