안녕하세요. 오늘은 React hook인 useCallback 와 memo 함수에 대해서 정리해 보겠습니다. 그전까지는 사람들이 사용하는 코드만 보고 제 프로젝트에도 적용해 봤지만 실제적으로 크게 필요한 부분에 사용하고 있지 않았습니다. 이번 기회에 확실하게 공부하고 가겠습니다!
예제 코드
App.tsx
import React, { useCallback, useState } from 'react';
import './App.css';
import Input from './components/Input';
import Btn from './components/Btn';
function App() {
const [input, setInput] = useState<string>('');
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const {value} = e.target;
setInput((prev: string) => {
return value;
})
}
const onClick = () => {
setInput('');
};
return (
<div className="App">
<div>{input}</div>
<Input onChange={onChange} value={input} />
<Btn onClick={onClick}/>
</div>
);
}
export default App;
Input.tsx
export default function Input(props: any) {
console.log('input');
return (
<input value={props.value} onChange={props.onChange} />
)
}
Btn.tsx
export default function Btn(props: any) {
console.log('button');
return (
<button onClick={props.onClick}>reset</button>
)
};
React에서 리랜더링 되는 3가지 조건이 있습니다. 첫 번째로는 부모의 컴포넌트가 리 랜더링 되었을 때, 두 번째로는 자신의 컴포넌트 state가 변견 되었을 때, 세 번째로는 부모가 넘겨준 props의 값이 변경되었을 때입니다.
위에 코드를 실행하면 아래의 사진처럼 나옵니다.
맨 처음으로 랜더링 되었을 때 input, button 컴포넌트가 랜더링 되는 과정에서 console.log 찍은 값들이 나오게 됩니다.
여기서 input에 값을 입력하게 되면
input에게 넘겨준 props의 값이 변경되어서 부모 컴포넌트가 리 랜더링 되어서 btn 컴포넌트까지 리 랜더링이 되었습니다.
버튼의 값은 변경된 것이 없지만 불필요한 랜더링이 생기는 것을 방지하기 위해서 React.memo함수를 사용해서 리 랜더링을 방지해보겠습니다.
React.memo
React.memo는 컴포넌트를 메모를 memoization 해주는데요. 리 랜더링 과정 속에서 자신의 컴포넌트가 변한 값이 없으면 랜더링을 방지해줍니다.
Btn.tsx
import { memo } from "react";
export default memo(function Btn(props: any) {
console.log('button');
return (
<button onClick={props.onClick}>reset</button>
)
})
이렇게 바꿔놓고 코드를 실행해 보겠습니다.
하지만...
결과는 똑같았습니다. 왜 그럴까요?
Btn에서 props로 onClick함수를 받았습니다. 부모 컴포넌트에서 리 랜더링과정에서 onclick을 다시 생성하면서 같은 함수 이지만 다른 주소값을 가지고 있어서 다른 함수로 인식해서 리랜더링되었던 것입니다.
여기서 useCallback hook을 사용해서 부모가 리랜더링 되었을 때 onclick함수를 그대로 기억해서 리 랜더링을 방지해 보겠습니다.
UseCallback
useCallback은 함수를 재사용할 수 있도록 해주는 react hook입니다. 위 예제를 보면 input의 값이 변경되는 과정에서 부모 컴포넌트인 app 컴포넌트가 리 랜더링 되었고 그 과정에서 onclick함수도 다시 생성되어서 memo가 제대로 사용되지 못했습니다.
import React, { useCallback, useState } from 'react';
import './App.css';
import Input from './components/Input';
import Btn from './components/Btn';
function App() {
const [input, setInput] = useState<string>('');
const onChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const {value} = e.target;
setInput((prev: string) => {
return value;
})
}, [])
const onClick = useCallback(() => {
setInput('');
}, []);
return (
<div className="App">
<div>{input}</div>
<Input onChange={onChange} value={input} />
<Btn onClick={onClick}/>
</div>
);
}
export default App;
위와 같이 useCallback를 사용해 주었습니다.
결과는...
변경된 input만 리 랜더링이 되었고, Btn 컴포넌트는 리랜더링이 안 일어난 것을 알 수 있습니다.
'coding > front-end' 카테고리의 다른 글
Next js 13 - app directory(Beta) (1) | 2023.03.09 |
---|---|
[React]Redux Toolkit (리덕스 툴킷)사용해 보기- Typescript (3) | 2022.05.10 |
[Next] 티스토리 OPEN API next.js 에서 적용하기(1) (1) | 2022.05.02 |
[Next.js]다크모드 구현하기 (sass) (8) | 2022.04.24 |
[Next]네이버 API - 로그인 구현 TypeScript (2) | 2022.04.20 |
댓글