์ ์ ํ ์ปดํฌ๋ํธ ์ ๋ฆฌ๋ฅผ ๊ฒ์ฆํ์ฌ React ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์๋ณํ๊ณ ๋ฐฉ์งํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ๊ณผ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ณดํธํ์ธ์.
React ๋ฉ๋ชจ๋ฆฌ ๋์ ๊ฐ์ง: ์ปดํฌ๋ํธ ์ ๋ฆฌ ๊ฒ์ฆ์ ๋ํ ํฌ๊ด์ ์ธ ๊ฐ์ด๋
React ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ ์ฑ๋ฅ์ ์กฐ์ฉํ ์ ํ์ํค๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์ด๋ฌํ ๋์๋ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋์์ง๋ง ๊ด๋ จ ๋ฆฌ์์ค(์: ํ์ด๋จธ, ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๋ฐ ๊ตฌ๋ )๊ฐ ์ ๋๋ก ์ ๋ฆฌ๋์ง ์์ ๋ ๋ฐ์ํฉ๋๋ค. ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ด๋ฌํ ํด์ ๋์ง ์์ ๋ฆฌ์์ค๊ฐ ๋์ ๋์ด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋นํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์๋๋ฅผ ๋ฆ์ถฅ๋๋ค. ์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ ์ ์ ํ ์ปดํฌ๋ํธ ์ ๋ฆฌ๋ฅผ ๊ฒ์ฆํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๊ฐ์งํ๊ณ ๋ฐฉ์งํ๊ธฐ ์ํ ์ ๋ต์ ์ ๊ณตํฉ๋๋ค.
React์์ ๋ฉ๋ชจ๋ฆฌ ๋์ ์ดํดํ๊ธฐ
๋ฉ๋ชจ๋ฆฌ ๋์๋ ์ปดํฌ๋ํธ๊ฐ DOM์์ ํด์ ๋์์ง๋ง ์ผ๋ถ JavaScript ์ฝ๋๊ฐ ์ฌ์ ํ ํด๋น ์ปดํฌ๋ํธ๋ฅผ ์ฐธ์กฐํ์ฌ ๊ฐ๋น์ง ์์ง๊ธฐ๊ฐ ์ ์ ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํ์ง ๋ชปํ๊ฒ ํ ๋ ๋ฐ์ํฉ๋๋ค. React๋ ์ปดํฌ๋ํธ ์๋ช ์ฃผ๊ธฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ์ง๋ง ๊ฐ๋ฐ์๋ ์ปดํฌ๋ํธ๊ฐ ์๋ช ์ฃผ๊ธฐ ๋์ ํ๋ํ ๋ชจ๋ ๋ฆฌ์์ค์ ๋ํ ์ ์ด ๊ถํ์ ํฌ๊ธฐํ๋๋ก ํด์ผ ํฉ๋๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์์ ์ผ๋ฐ์ ์ธ ์์ธ:
- ๋ช
ํํ์ง ์์ ํ์ด๋จธ ๋ฐ ๊ฐ๊ฒฉ: ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ํ์๋ ํ์ด๋จธ(
setTimeout
,setInterval
)๋ฅผ ๊ณ์ ์คํํ๋ ๊ฒฝ์ฐ. - ์ ๊ฑฐ๋์ง ์์ ์ด๋ฒคํธ ๋ฆฌ์ค๋:
window
,document
๋๋ ๋ค๋ฅธ DOM ์์์ ์ฐ๊ฒฐ๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ ๊ฑฐํ์ง ๋ชปํ ๊ฒฝ์ฐ. - ์๋ฃ๋์ง ์์ ๊ตฌ๋ : observable(์: RxJS) ๋๋ ๊ธฐํ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๊ตฌ๋ ์ทจ์ํ์ง ์์ ๊ฒฝ์ฐ.
- ํด์ ๋์ง ์์ ๋ฆฌ์์ค: ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋๋ API์์ ์ป์ ๋ฆฌ์์ค๋ฅผ ํด์ ํ์ง ์์ ๊ฒฝ์ฐ.
- ํด๋ก์ : ์ปดํฌ๋ํธ ๋ด์์ ์ปดํฌ๋ํธ์ ์ํ ๋๋ props์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ถ์ฃผ์ํ๊ฒ ์บก์ฒํ๊ณ ์ ์งํ๋ ํจ์.
๋ฉ๋ชจ๋ฆฌ ๋์ ๊ฐ์ง
๊ฐ๋ฐ ์ฃผ๊ธฐ ์ด๊ธฐ์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์๋ณํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ช ๊ฐ์ง ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ๊ฐ์งํ ์ ์์ต๋๋ค.
1. ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ
์ต์ ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ๋ ๊ฐ๋ ฅํ ๋ฉ๋ชจ๋ฆฌ ํ๋กํ์ผ๋ง ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ํนํ Chrome DevTools๊ฐ ๋งค์ฐ ํจ๊ณผ์ ์ ๋๋ค.
- ํ ์ค๋ ์ท ์ฐ๊ธฐ: ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฉ๋ชจ๋ฆฌ ์ค๋ ์ท์ ์๋ก ๋ค๋ฅธ ์์ ์ ์บก์ฒํฉ๋๋ค. ์ค๋ ์ท์ ๋น๊ตํ์ฌ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ํ ๊ฐ๋น์ง ์์ง๋์ง ์๋ ๊ฐ์ฒด๋ฅผ ์๋ณํฉ๋๋ค.
- ํ ๋น ํ์๋ผ์ธ: ํ ๋น ํ์๋ผ์ธ์ ์๊ฐ์ ๋ฐ๋ฅธ ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ ๋ณด์ฌ์ค๋๋ค. ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋๊ณ ๋ง์ดํธ ํด์ ๋ ๋์๋ ๋ฉ๋ชจ๋ฆฌ ์๋น๊ฐ ์ฆ๊ฐํ๋์ง ํ์ธํฉ๋๋ค.
- ์ฑ๋ฅ ํญ: ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์งํ๋ ํจ์๋ฅผ ์๋ณํ๊ธฐ ์ํด ์ฑ๋ฅ ํ๋กํ์ ๊ธฐ๋กํฉ๋๋ค.
์์ (Chrome DevTools):
- Chrome DevTools ์ด๊ธฐ (Ctrl+Shift+I ๋๋ Cmd+Option+I).
- "Memory" ํญ์ผ๋ก ์ด๋ํฉ๋๋ค.
- "Heap snapshot"์ ์ ํํ๊ณ "Take snapshot"์ ํด๋ฆญํฉ๋๋ค.
- ์ปดํฌ๋ํธ ๋ง์ดํธ ๋ฐ ๋ง์ดํธ ํด์ ๋ฅผ ํธ๋ฆฌ๊ฑฐํ๋ ค๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ์ํธ ์์ฉํฉ๋๋ค.
- ๋ค๋ฅธ ์ค๋ ์ท์ ์ฐ์ต๋๋ค.
- ๋ ์ค๋ ์ท์ ๋น๊ตํ์ฌ ๊ฐ๋น์ง ์์ง๋์์ด์ผ ํ์ง๋ง ๊ทธ๋ ์ง ์์ ๊ฐ์ฒด๋ฅผ ์ฐพ์ต๋๋ค.
2. React DevTools Profiler
React DevTools๋ ๋ฉ๋ชจ๋ฆฌ ๋์๋ก ์ธํด ๋ฐ์ํ๋ ๊ฒ์ ํฌํจํ์ฌ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํ๋ ๋ฐ ๋์์ด ๋๋ ํ๋กํ์ผ๋ฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ง์ ๊ฐ์งํ์ง๋ ์์ง๋ง ์์๋๋ก ์๋ํ์ง ์๋ ์ปดํฌ๋ํธ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
3. ์ฝ๋ ๊ฒํ
ํนํ ์ปดํฌ๋ํธ ์ ๋ฆฌ ๋ก์ง์ ์ด์ ์ ๋ง์ถ ์ ๊ธฐ์ ์ธ ์ฝ๋ ๊ฒํ ๋ ์ ์ฌ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ํฌ์ฐฉํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. ์ ๋ฆฌ ํจ์๊ฐ ์๋ useEffect
ํ
์ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ด๊ณ ๋ชจ๋ ํ์ด๋จธ, ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๋ฐ ๊ตฌ๋
์ด ์ ๋๋ก ๊ด๋ฆฌ๋๋์ง ํ์ธํฉ๋๋ค.
4. ํ ์คํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
Jest ๋ฐ React Testing Library์ ๊ฐ์ ํ ์คํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ํน๋ณํ ํ์ธํ๋ ํตํฉ ํ ์คํธ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์ด๋ฌํ ํ ์คํธ๋ ์ปดํฌ๋ํธ ๋ง์ดํธ ๋ฐ ๋ง์ดํธ ํด์ ๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๊ณ ๋ฆฌ์์ค๊ฐ ์ ์ง๋์ง ์๋์ง ํ์ธํ ์ ์์ต๋๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง: ๋ชจ๋ฒ ์ฌ๋ก
๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ์ฒ์๋ถํฐ ๋ฐ์ํ๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๊ฒ์ ๋๋ค. ๋ค์์ ๋ฐ๋ผ์ผ ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก์ ๋๋ค.
1. ์ ๋ฆฌ ํจ์์ ํจ๊ป useEffect
์ฌ์ฉ
useEffect
ํ
์ ํจ์ํ ์ปดํฌ๋ํธ์์ ์ฌ์ด๋ ์ดํํธ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ๊ธฐ๋ณธ ๋ฉ์ปค๋์ฆ์
๋๋ค. ํ์ด๋จธ, ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๋๋ ๊ตฌ๋
์ ์ฒ๋ฆฌํ ๋๋ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ๋ ์ด๋ฌํ ๋ฆฌ์์ค๋ฅผ ๋ฑ๋ก ํด์ ํ๋ ์ ๋ฆฌ ํจ์๋ฅผ ํญ์ ์ ๊ณตํฉ๋๋ค.
์์:
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setCount(prevCount => prevCount + 1);
}, 1000);
return () => {
clearInterval(intervalId);
console.log('Timer cleared!');
};
}, []);
return (
Count: {count}
);
}
export default MyComponent;
์ด ์์ ์์ useEffect
ํ
์ 1์ด๋ง๋ค count
์ํ๋ฅผ ์ฆ๊ฐ์ํค๋ ๊ฐ๊ฒฉ์ ์ค์ ํฉ๋๋ค. ์ ๋ฆฌ ํจ์(useEffect
์์ ๋ฐํ)๋ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ๋ ๊ฐ๊ฒฉ์ ์ง์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
2. ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ ๊ฑฐ
window
, document
๋๋ ๊ธฐํ DOM ์์์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ฒจ๋ถํ๋ ๊ฒฝ์ฐ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ๋ ํด๋น ๋ฆฌ์ค๋๋ฅผ ์ ๊ฑฐํด์ผ ํฉ๋๋ค.
์์:
import React, { useEffect } from 'react';
function MyComponent() {
const handleScroll = () => {
console.log('Scrolled!');
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
console.log('Scroll listener removed!');
};
}, []);
return (
Scroll this page.
);
}
export default MyComponent;
์ด ์์ ๋ window
์ ์คํฌ๋กค ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ฒจ๋ถํฉ๋๋ค. ์ ๋ฆฌ ํจ์๋ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
3. Observables ๊ตฌ๋ ์ทจ์
์ ํ๋ฆฌ์ผ์ด์ ์ด observable(์: RxJS)์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ๋ ํด๋น observable์ ๊ตฌ๋ ์ ์ทจ์ํด์ผ ํฉ๋๋ค. ๊ทธ๋ ๊ฒ ํ์ง ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐ ์๊ธฐ์น ์์ ๋์์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
์์ (RxJS ์ฌ์ฉ):
import React, { useState, useEffect } from 'react';
import { interval } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
function MyComponent() {
const [count, setCount] = useState(0);
const destroy$ = new Subject();
useEffect(() => {
interval(1000)
.pipe(takeUntil(destroy$))
.subscribe(val => {
setCount(val);
});
return () => {
destroy$.next();
destroy$.complete();
console.log('Subscription unsubscribed!');
};
}, []);
return (
Count: {count}
);
}
export default MyComponent;
์ด ์์ ์์ observable(interval
)์ 1์ด๋ง๋ค ๊ฐ์ ๋ฐฉ์ถํฉ๋๋ค. takeUntil
์ฐ์ฐ์๋ destroy$
subject๊ฐ ๊ฐ์ ๋ฐฉ์ถํ ๋ observable์ด ์๋ฃ๋๋๋ก ํฉ๋๋ค. ์ ๋ฆฌ ํจ์๋ destroy$
์์ ๊ฐ์ ๋ฐฉ์ถํ๊ณ ์๋ฃํ์ฌ observable์ ๊ตฌ๋
์ ์ทจ์ํฉ๋๋ค.
4. Fetch API์ AbortController
์ฌ์ฉ
Fetch API๋ฅผ ์ฌ์ฉํ์ฌ API ํธ์ถ์ ํ ๋ ์์ฒญ์ด ์๋ฃ๋๊ธฐ ์ ์ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋๋ ๊ฒฝ์ฐ AbortController
๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒญ์ ์ทจ์ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ถํ์ํ ๋คํธ์ํฌ ์์ฒญ๊ณผ ์ ์ฌ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
์์:
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortController = new AbortController();
const signal = abortController.signal;
const fetchData = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1', { signal });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const json = await response.json();
setData(json);
} catch (e) {
if (e.name === 'AbortError') {
console.log('Fetch aborted');
} else {
setError(e);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => {
abortController.abort();
console.log('Fetch aborted!');
};
}, []);
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
return (
Data: {JSON.stringify(data)}
);
}
export default MyComponent;
์ด ์์ ์์๋ AbortController
๊ฐ ์์ฑ๋๊ณ ํด๋น ์ ํธ๊ฐ fetch
ํจ์์ ์ ๋ฌ๋ฉ๋๋ค. ์์ฒญ์ด ์๋ฃ๋๊ธฐ ์ ์ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋๋ฉด abortController.abort()
๋ฉ์๋๊ฐ ํธ์ถ๋์ด ์์ฒญ์ด ์ทจ์๋ฉ๋๋ค.
5. ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ ์ ์งํ๊ธฐ ์ํด useRef
์ฌ์ฉ
๊ฒฝ์ฐ์ ๋ฐ๋ผ ์ฌ ๋ ๋๋ง์ ๋ฐ์์ํค์ง ์๊ณ ์ฌ ๋ ๋๋ง์์ ์ง์๋๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ ์ ์งํด์ผ ํ ์ ์์ต๋๋ค. useRef
ํ
์ ์ด๋ฌํ ๋ชฉ์ ์ ์ด์์ ์
๋๋ค. ์ด๋ ์ ๋ฆฌ ํจ์์์ ์ก์ธ์คํด์ผ ํ๋ ํ์ด๋จธ ๋๋ ๊ธฐํ ๋ฆฌ์์ค์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์ฅํ๋ ๋ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
์์:
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const timerId = useRef(null);
useEffect(() => {
timerId.current = setInterval(() => {
console.log('Tick');
}, 1000);
return () => {
clearInterval(timerId.current);
console.log('Timer cleared!');
};
}, []);
return (
Check the console for ticks.
);
}
export default MyComponent;
์ด ์์ ์์ timerId
ref๋ ๊ฐ๊ฒฉ์ ID๋ฅผ ์ ์งํฉ๋๋ค. ์ ๋ฆฌ ํจ์๋ ์ด ID์ ์ก์ธ์คํ์ฌ ๊ฐ๊ฒฉ์ ์ง์ธ ์ ์์ต๋๋ค.
6. ๋ง์ดํธ ํด์ ๋ ์ปดํฌ๋ํธ์์ ์ํ ์ ๋ฐ์ดํธ ์ต์ํ
์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ํ ํด๋น ์ปดํฌ๋ํธ์์ ์ํ๋ฅผ ์ค์ ํ์ง ๋ง์ธ์. React๋ ์ด๋ฌํ ์์
์ ์๋ํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐ ์๊ธฐ์น ์์ ๋์์ผ๋ก ์ด์ด์ง ์ ์์ผ๋ฏ๋ก ๊ฒฝ๊ณ ํฉ๋๋ค. isMounted
ํจํด ๋๋ AbortController
๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฌํ ์
๋ฐ์ดํธ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
์์ (AbortController
๋ฅผ ์ฌ์ฉํ์ฌ ์ํ ์
๋ฐ์ดํธ ๋ฐฉ์ง - ์น์
4์ ์์ ์ฐธ์กฐ):
AbortController
์ ๊ทผ ๋ฐฉ์์ "Fetch API์ AbortController
์ฌ์ฉ" ์น์
์ ๋์ ์์ผ๋ฉฐ ๋น๋๊ธฐ ํธ์ถ์์ ๋ง์ดํธ ํด์ ๋ ์ปดํฌ๋ํธ์์ ์ํ ์
๋ฐ์ดํธ๋ฅผ ๋ฐฉ์งํ๋ ๊ถ์ฅ ๋ฐฉ๋ฒ์
๋๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์ ํ ์คํธ
๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ํน๋ณํ ํ์ธํ๋ ํ ์คํธ๋ฅผ ์์ฑํ๋ ๊ฒ์ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ์์ค๋ฅผ ์ ๋๋ก ์ ๋ฆฌํ๊ณ ์๋์ง ํ์ธํ๋ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์ ๋๋ค.
1. Jest ๋ฐ React Testing Library๋ฅผ ์ฌ์ฉํ ํตํฉ ํ ์คํธ
Jest ๋ฐ React Testing Library๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ ๋ง์ดํธ ๋ฐ ๋ง์ดํธ ํด์ ๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๊ณ ๋ฆฌ์์ค๊ฐ ์ ์ง๋์ง ์๋์ง ํ์ธํ ์ ์์ต๋๋ค.
์์:
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import MyComponent from './MyComponent'; // ์ค์ ์ปดํฌ๋ํธ ๊ฒฝ๋ก๋ก ๋ฐ๊พธ์ธ์
// ๊ฐ๋น์ง ์์ง์ ๊ฐ์ ๋ก ์ํํ๋ ๊ฐ๋จํ ๋์ฐ๋ฏธ ํจ์ (์ ๋ขฐํ ์ ์์ง๋ง, ๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋์์ด ๋ ์ ์์)
function forceGarbageCollection() {
if (global.gc) {
global.gc();
}
}
describe('MyComponent', () => {
let container = null;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
unmountComponentAtNode(container);
container.remove();
container = null;
forceGarbageCollection();
});
it('should not leak memory', async () => {
const initialMemory = performance.memory.usedJSHeapSize;
render( , container);
unmountComponentAtNode(container);
forceGarbageCollection();
// ๊ฐ๋น์ง ์์ง์ด ๋ฐ์ํ ๋๊น์ง ์ ์ ๊ธฐ๋ค๋ฆฝ๋๋ค.
await new Promise(resolve => setTimeout(resolve, 500));
const finalMemory = performance.memory.usedJSHeapSize;
expect(finalMemory).toBeLessThan(initialMemory + 1024 * 100); // ์ฝ๊ฐ์ ์ค์ฐจ ํ์ฉ (100KB)
});
});
์ด ์์ ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ , ๋ง์ดํธ ํด์ ํ๊ณ , ๊ฐ๋น์ง ์์ง์ ๊ฐ์ ๋ก ์ํํ ๋ค์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ํฌ๊ฒ ์ฆ๊ฐํ๋์ง ํ์ธํฉ๋๋ค. ์ฐธ๊ณ : performance.memory
๋ ์ผ๋ถ ๋ธ๋ผ์ฐ์ ์์ ๋ ์ด์ ์ฌ์ฉ๋์ง ์์ผ๋ฏ๋ก ํ์ํ ๊ฒฝ์ฐ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํ์ธ์.
2. Cypress ๋๋ Selenium์ ์ฌ์ฉํ ์ข ๋จ ๊ฐ ํ ์คํธ
์ฌ์ฉ์ ์ํธ ์์ฉ์ ์๋ฎฌ๋ ์ด์ ํ๊ณ ์๊ฐ ๊ฒฝ๊ณผ์ ๋ฐ๋ฅธ ๋ฉ๋ชจ๋ฆฌ ์๋น๋ฅผ ๋ชจ๋ํฐ๋งํ์ฌ ์ข ๋จ ๊ฐ ํ ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๊ฐ์งํ ์๋ ์์ต๋๋ค.
์๋ ๋ฉ๋ชจ๋ฆฌ ๋์ ๊ฐ์ง ๋๊ตฌ
๋ช ๊ฐ์ง ๋๊ตฌ๋ ๋ฉ๋ชจ๋ฆฌ ๋์ ๊ฐ์ง ํ๋ก์ธ์ค๋ฅผ ์๋ํํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- MemLab (Facebook): ์คํ ์์ค JavaScript ๋ฉ๋ชจ๋ฆฌ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค.
- LeakCanary (Square - Android, ํ์ง๋ง ๊ฐ๋ ์ ์ฉ): ์ฃผ๋ก Android์ฉ์ด์ง๋ง ๋์ ๊ฐ์ง ์๋ฆฌ๋ JavaScript์๋ ์ ์ฉ๋ฉ๋๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์ ๋๋ฒ๊น : ๋จ๊ณ๋ณ ์ ๊ทผ ๋ฐฉ์
๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ์์ฌ๋๋ ๊ฒฝ์ฐ ๋ค์ ๋จ๊ณ๋ฅผ ์ํํ์ฌ ๋ฌธ์ ๋ฅผ ์๋ณํ๊ณ ํด๊ฒฐํฉ๋๋ค.
- ๋์ ์ฌํ: ๋์๋ฅผ ํธ๋ฆฌ๊ฑฐํ๋ ํน์ ์ฌ์ฉ์ ์ํธ ์์ฉ ๋๋ ์ปดํฌ๋ํธ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์๋ณํฉ๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ํ๋กํ์ผ๋ง: ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ ์ค๋ ์ท ๋ฐ ํ ๋น ํ์๋ผ์ธ์ ์บก์ฒํฉ๋๋ค.
- ๋์ ๊ฐ์ฒด ์๋ณ: ํ ์ค๋ ์ท์ ๋ถ์ํ์ฌ ๊ฐ๋น์ง ์์ง๋์ง ์๋ ๊ฐ์ฒด๋ฅผ ์ฐพ์ต๋๋ค.
- ๊ฐ์ฒด ์ฐธ์กฐ ์ถ์ : ์ฝ๋์ ์ด๋ค ๋ถ๋ถ์ด ๋์ ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์งํ๋์ง ํ์ธํฉ๋๋ค.
- ๋์ ์์ : ์ ์ ํ ์ ๋ฆฌ ๋ก์ง(์: ํ์ด๋จธ ์ง์ฐ๊ธฐ, ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ ๊ฑฐ, observable ๊ตฌ๋ ์ทจ์)์ ๊ตฌํํฉ๋๋ค.
- ์์ ์ฌํญ ํ์ธ: ํ๋กํ์ผ๋ง ํ๋ก์ธ์ค๋ฅผ ๋ฐ๋ณตํ์ฌ ๋์๊ฐ ํด๊ฒฐ๋์๋์ง ํ์ธํฉ๋๋ค.
๊ฒฐ๋ก
๋ฉ๋ชจ๋ฆฌ ๋์๋ React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ๊ณผ ์์ ์ฑ์ ์๋นํ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ๋ฉ๋ชจ๋ฆฌ ๋์์ ์ผ๋ฐ์ ์ธ ์์ธ์ ์ดํดํ๊ณ , ์ปดํฌ๋ํธ ์ ๋ฆฌ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๊ณ , ์ ์ ํ ๊ฐ์ง ๋ฐ ๋๋ฒ๊น ๋๊ตฌ๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ์ด๋ฌํ ๋ฌธ์ ๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ํฅ์ ๋ฏธ์น๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ์ ๊ธฐ์ ์ธ ์ฝ๋ ๊ฒํ , ์ฒ ์ ํ ํ ์คํธ ๋ฐ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ๋ํ ์ฌ์ ์๋ฐฉ์ ์ ๊ทผ ๋ฐฉ์์ ๊ฐ๋ ฅํ๊ณ ์ฑ๋ฅ์ด ๋ฐ์ด๋ React ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ์๋ฐฉ์ด ์น๋ฃ๋ณด๋ค ํญ์ ๋ ๋ซ๋ค๋ ๊ฒ์ ๊ธฐ์ตํ์ญ์์ค. ์ฒ์๋ถํฐ ๋ถ์ง๋ฐํ ์ ๋ฆฌ๋ ๋์ค์ ์๋นํ ๋๋ฒ๊น ์๊ฐ์ ์ ์ฝํด ์ค ๊ฒ์ ๋๋ค.