useMemo를 사용하는 이유
React가 값을 기억해서 불필요한 Re-Rendering하는 것을 막기위해 사용한다.
Memo는 memoization의 약자로 이전의 계산한 값을 재사용한다는 뜻이다.
useMemo 사용법
const 변수이름 = useMemo(() => 호출할함수(a, b), [a, b]);
useMemo의 첫 번째 파라미터 : 호출할 함수
useMemo의 두 번째 파라미터 : 의존성(deps) 배열
아래 예시를 통해 확인하자.
사용자를 등록하고 전체 사용자 정보와 전체 사용자 수를 화면에 표시하는 코드를 작성하자.
우선 useMemo를 사용하지 않고 작성하면 다음과 같다.
App.js
import React, { useRef, useState } from "react";
const countUser = (users) => {
console.log("전체 사용자 수 계산중");
return users.length;
};
const App = () => {
// Input 저장
const [inputs, setInputs] = useState({
name: "",
feel: "",
});
// 비구조화 할당을 통해 Input 값 추출
const { name, feel } = inputs;
// user 정보 저장
const [users, setUsers] = useState([
{
id: 1,
name: "navy",
feel: "good",
},
{
id: 2,
name: "army",
feel: "soso",
},
]);
// id 늘리기 위해
const id = useRef(2);
// Input 내용이 바뀔 때 호출
const onChange = (e) => {
const { name, value } = e.target;
setInputs({ ...inputs, [name]: value });
};
// 등록 버튼을 누를 때 호출
const onSubmit = (e) => {
e.preventDefault();
id.current += 1;
setUsers([
...users,
{
id: id.current,
name: name,
feel: feel,
},
]);
};
// 전체 사용자수 받아오기
const numberOfUser = countUser(users);
return (
<div>
<div>
<form onSubmit={onSubmit}>
<input name="name" value={name} onChange={onChange} placeholder="이름"/>
<input name="feel" value={feel} onChange={onChange} placeholder="기분"/>
<input value="등록" type="submit" />
</form>
</div>
{users.map((user) => {
return (
<div key={user.id}>
아이디 : {user.id} 이름 : {user.name} 기분 : {user.feel}
</div>
);
})}
전체 사용자 수 : {numberOfUser}
</div>
);
};
export default App;
위 코드는 효율적이지 않다. 왜냐하면 이름과 기분을 입력할 때마다 inputs의 State가 변화되면서 App 컴포넌트가 Re-Rendering되기 때문이다.
즉, Re-Rendering될 때마다 const numberOfUser = countUser(users); 코드에 의해 countUser 함수가 호출되고 그때 마다 전체 사용자의 수를 계산하게 된다.
아래는 위의 코드 실행화면이다. Input에 값을 입력할 때마다 countUser함수가 계속 출력되는 것을 볼 수 있다.
우리는 새로운 사용자가 등록되었을 때만 countUser 함수를 호출해 전체 사용자수를 계산하고 싶다.
useMemo를 사용하여 [users]가 바뀔때만 해당 함수를 호출하게 코드를 추가한다.
최종 코드는 다음과 같다.
App.js
import React, { useMemo, useRef, useState } from "react";
const countUser = (users) => {
console.log("전체 사용자 수 계산중");
return users.length;
};
const App = () => {
// Input 저장
const [inputs, setInputs] = useState({
name: "",
feel: "",
});
// 비구조화 할당을 통해 Input 값 추출
const { name, feel } = inputs;
// user 정보 저장
const [users, setUsers] = useState([
{
id: 1,
name: "navy",
feel: "good",
},
{
id: 2,
name: "army",
feel: "soso",
},
]);
// id 늘리기 위해
const id = useRef(2);
// Input 내용이 바뀔 때 호출
const onChange = (e) => {
const { name, value } = e.target;
setInputs({ ...inputs, [name]: value });
};
// 등록 버튼을 누를 때 호출
const onSubmit = (e) => {
e.preventDefault();
id.current += 1;
setUsers([
...users,
{
id: id.current,
name: name,
feel: feel,
},
]);
};
// useMemo를 사용하여 users가 변할때만 countUser 함수 호출
const numberOfUser = useMemo(() => countUser(users), [users]);
return (
<div>
<div>
<form onSubmit={onSubmit}>
<input name="name" value={name} onChange={onChange} placeholder="이름"></input>
<input name="feel" value={feel} onChange={onChange} placeholder="기분"></input>
<input value="등록" type="submit" />
</form>
</div>
{users.map((user) => {
return (
<div key={user.id}>
아이디 : {user.id} 이름 : {user.name} 기분 : {user.feel}
</div>
);
})}
총 사용자 수 : {numberOfUser}
</div>
);
};
export default App;