1. useCallback : useCallback()은 함수를 메모이제이션(memoization)하기 위해서 사용되는 hook 함수입니다. 첫번째 인자로 넘어온 함수를, 두번째 인자로 넘어온 배열 내의 값이 변경될 때까지 저장해놓고 재사용할 수 있게 해줍니다.
아래 코드에서는 컴포넌트의 랜더링이 일어날때마다 onSave라는 함수를 생성해서 자식에게 넘겨준다
import { useState } from 'react';
import TestTwo from './frag/test-two';
const TestPage = () => {
const [name, setName] = useState('');
const onSave = () => {
console.log('hello.');
};
return (
<div className="App">
<input type="text" value={name} onChange={e => setName(e.target.value)} />
<TestTwo onSave={onSave} />
</div>
);
};
export default TestPage;
즉, 아래 인풋에 값을 넣을때마다 Profile컴포넌트의 랜더링이 일어난다
이렇게 바꿔주었다.
import { useCallback, useState } from 'react';
import TestTwo from './frag/test-two';
const TestPage = () => {
const [name, setName] = useState('');
const onSave = useCallback(() => {
console.log('hello.');
}, []);
return (
<div className="App">
<input type="text" value={name} onChange={e => setName(e.target.value)} />
<TestTwo onSave={onSave} />
</div>
);
};
export default TestPage;
이제 useState의 변경으로 리랜더링이 되더라도 TestTwo의 컴포넌트가 랜더링이 되지 않음을 알수있다.
새로 함수가 생성되지 않기 때문이다.
그렇다면 버튼을 누르면 onSave안에 input에 입력한 값을 출력하게 해보자.
import { useCallback, useState } from 'react';
import TestTwo from './frag/test-two';
const TestPage = () => {
const [name, setName] = useState('');
const onSave = useCallback(() => {
console.log(name);
}, []);
return (
<div className="App">
<input type="text" value={name} onChange={e => setName(e.target.value)} />
<TestTwo onSave={onSave} />
</div>
);
};
export default TestPage;
const TestTwo = ({ onSave }) => {
return <button onClick={onSave}>눌러요</button>;
};
export default TestTwo;
아무리 눌러도 입력한 input의 값이 콘솔에 찍히지 않는다.
왜냐하면 onSave콜백함수의 인자에 아무값도 넣지 않아서 함수의 재선언이 일어나지 않았기 때문이다.
아래와 같이 useCallback의 인자에 name을 넣어주면 name의 값이 변경될 때만 재선언이 일어나서 정상 작동을 하게 된다. input에 값을 입력할 때마다 TestTwo컴포넌트에 불이 들어오는 것도 볼 수 있다.
import { useCallback, useState } from 'react';
import TestTwo from './frag/test-two';
const TestPage = () => {
const [name, setName] = useState('');
const onSave = useCallback(() => {
console.log(name);
}, [name]);
return (
<div className="App">
<input type="text" value={name} onChange={e => setName(e.target.value)} />
<TestTwo onSave={onSave} />
</div>
);
};
export default TestPage;
2. useMemo
useMemo를 사용하지 않는 다면, 아래와 같은 컴포넌트에서 글자를 변경하지 않고 숫자만 변경해도 getNumber, getText함수가 실행되게 된다.
import { useCallback, useState } from 'react';
import TestTwo from './frag/test-two';
const TestPage = () => {
const [number, setNumber] = useState(0);
const [text, setText] = useState('');
const increaseNumber = () => {
setNumber(prevState => prevState + 1);
};
const decreaseNumber = () => {
setNumber(prevState => prevState - 1);
};
const onChangeTextHandler = (e: any) => {
setText(e.target.value);
};
return (
<div className="App">
<div>
<button onClick={increaseNumber}>+</button>
<button onClick={decreaseNumber}>-</button>
<input type="text" placeholder="Last Name" onChange={onChangeTextHandler} />
</div>
<TestTwo number={number} text={text} />
</div>
);
};
export default TestPage;
const getNumber = (number: any) => {
console.log('숫자가 변동되었습니다.');
return number;
};
const getText = (text: any) => {
console.log('글자가 변동되었습니다.');
return text;
};
const TestTwo = ({ number, text }: any) => {
const showNumber = getNumber(number);
const showText = getText(text);
return (
<div className="info-wrapper">
{showNumber} <br />
{showText}
</div>
);
};
export default TestTwo;
그렇다면 useCallback을 쓰면 어떻게 될까?
import { useCallback, useState } from 'react';
import TestTwo from './frag/test-two';
const TestPage = () => {
const [number, setNumber] = useState(0);
const [text, setText] = useState('');
const increaseNumber = useCallback(() => {
setNumber(prevState => prevState + 1);
}, []);
const decreaseNumber = useCallback(() => {
setNumber(prevState => prevState - 1);
}, []);
const onChangeTextHandler = useCallback((e: any) => {
setText(e.target.value);
}, []);
return (
<div className="App">
<div>
<button onClick={increaseNumber}>+</button>
<button onClick={decreaseNumber}>-</button>
<input type="text" placeholder="Last Name" onChange={onChangeTextHandler} />
</div>
<TestTwo number={number} text={text} />
</div>
);
};
export default TestPage;
import { useCallback } from 'react';
const TestTwo = ({ number, text }: any) => {
const getNumber = useCallback((numbert: any) => {
console.log('숫자가 변동되었습니다.');
return number;
}, []);
const getText = useCallback((textt: any) => {
console.log('글자가 변동되었습니다.');
return text;
}, []);
const showNumber = getNumber(number);
const showText = getText(text);
return (
<div className="info-wrapper">
{showNumber} <br />
{showText}
</div>
);
};
export default TestTwo;
버튼이 클릭되면 함수가 실행되기 때문에 useCallback이 있던 없던 상관이 없었다.
이제 useMemo를 써보면은 숫자만 변경됐을때는 숫자가 변경되었습니다 만 콘솔에 뜨고 글자만 변경됐을때는 글자만 변경되었습니다 라고 콘솔에 뜬다!!
import { useCallback, useState } from 'react';
import TestTwo from './frag/test-two';
const TestPage = () => {
const [number, setNumber] = useState(0);
const [text, setText] = useState('');
const increaseNumber = () => {
setNumber(prevState => prevState + 1);
};
const decreaseNumber = () => {
setNumber(prevState => prevState - 1);
};
const onChangeTextHandler = (e: any) => {
setText(e.target.value);
};
return (
<div className="App">
<div>
<button onClick={increaseNumber}>+</button>
<button onClick={decreaseNumber}>-</button>
<input type="text" placeholder="Last Name" onChange={onChangeTextHandler} />
</div>
<TestTwo number={number} text={text} />
</div>
);
};
export default TestPage;
import { useMemo } from 'react';
const getNumber = (number: any) => {
console.log('숫자가 변동되었습니다.');
return number;
};
const getText = (text: any) => {
console.log('글자가 변동되었습니다.');
return text;
};
const TestTwo = ({ number, text }: any) => {
const showNumber = useMemo(() => getNumber(number), []);
const showText = useMemo(() => getText(text), []);
return (
<div className="info-wrapper">
{showNumber} <br />
{showText}
</div>
);
};
export default TestTwo;
참고)
랜더링 될때마다 표시되는 google extension : React Developer Tools
'Next' 카테고리의 다른 글
next14) use server에서 use client 컴포넌트를 import해서 사용하는 방법 (0) | 2024.08.18 |
---|---|
NextJS로 tailwind시작하기 (0) | 2023.12.13 |
저장 시 prettier 작동하도록 설정하는 법 (format on save) (0) | 2023.10.18 |
javascript 요일 알아내기 .getDay() (0) | 2023.08.15 |