useCallback
은 useMemo
와 비슷한 Hook
useMemo
는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback
은 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용
함수를 선언할때마다 메모리나 CPU 리소스를 많이 차지 하는 작업은 아니지만, 한번 만든 함수를 필요할 때만 새로 만들고 재사용하는 것은 중요하다.
이유 : 나중에 컴포넌트에서 props
가 바뀌지 않았으면 Virtual DOM에 새로 렌더링 하는 것 조차 하지 않고 컴포넌트의 결과물을 재사용 하는 최적화하는 작업을 하려면 함수를 재사용하는 것은 필수
App.js
// import logo from './logo.svg';
// import './App.css';
import React, { useRef, useState, useMemo, useCallback } from "react";
import CreateUser from "./CreateUser";
import UserList from "./UserList";
function countActiveUsers(users) {
console.log('활성 사용자 수를 세는 중...');
return users.filter(user => user.active).length;
};
function App() {
const [inputs, setInputs] = useState({
username: '',
email: ''
});
const { username, email } = inputs;
const onChange = useCallback(e => {
const {name, value} = e.target;
setInputs({
...inputs,
[name] : value
});
}, [inputs]);
const [users, setUsers] = useState([
{
id: 1,
username: 'jini',
email: 'genie9105@gamail.com',
active: true
},
{
id: 2,
username: 'biki',
email: 'biki@gmail.com',
active: false
},
{
id: 3,
username: 'nado',
email: 'nado@gmail.com',
active: false
}
]);
const nextId = useRef(4); //useref의 초기값은 4
const onCreate = useCallback(() => {
const user = {
id: nextId.current,
username,
email
};
// setUsers([...users, user]); 1번째 방법
setUsers(users.concat(user)); //2번째 방법
setInputs({
username: '',
email: ''
});
nextId.current += 1;
}, [username, email, users]);
const onRemove = useCallback(id => {
// user.id가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
// = user.id가 id 인 것을 제거함
setUsers(users.filter(user => user.id !== id))
}, [users]);
const onToggle = useCallback(id => {
setUsers(users.map(
user => user.id === id
?{...user, active: !user.active}
: user
));
}, [users]);
const count = useMemo(() => countActiveUsers(users), [users]);
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate ={onCreate}
/>
<UserList users={users} onRemove={onRemove} onToggle={onToggle}/>
<div>활성 사용자 수 : {count}</div>
</>
);
}
export default App;
onCreate
, onRemove
, onToggle
함수를 useCallback
으로 감싸준다.
주의할 점은, 함수 안에서 사용하는 state
나 props
가 있다면, deps
배열안에 포함 시켜야 됨
만약 deps
배열 안에 함수에서 사용하는 값을 넣지 않게 된다면, 함수 내에서 해당 값들을 참조할 때 가장 최신 값을 참조 할 것이라고 보장할 수 없다. props
로 받아온 함수가 있다면, 이또한 deps
에 넣어주어야 한다.
useCallback
은 useMemo
를 기반으로 만들어졌다. 다만, 함수를 위해서 사용 할 때 더욱 편하게 해준 것 뿐, 아래와 같이 표현 가능
const onToggle = useMemo(
() => () => {
/* ... */
},
[users]
);
UseList.js
import React from "react";
function User({ user, onRemove, onToggle }) {
const { username, email, id, active } = user;
return (
<div>
<b
style={{
color: active ? 'green' : 'black',
cursor: 'pointer'
}}
onClick={() => onToggle(id)}
>
{username}
</b>
<span>({email})</span>
<button onClick={() => onRemove(id)}>삭제</button>
</div>
);
}
function UserList({ users, onRemove, onToggle }) {
return (
<div>
{
users.map(
user => (
<User
user={user}
key={user.id}
onRemove={onRemove}
onToggle={onToggle}
/>
)
)
}
</div>
)
}
export default UserList;
CreateList.js
import React from "react";
//onChange는 이 텍스트(input)값이 바뀌게 될때, onCreate는 버튼을 눌렀을 때 새로운 항목을 등록해주는 함수
function CreateUser({ username, email, onChange, onCreate }) {
return (
<div>
<input
name="username"
placeholder="계정명"
onChange={onChange}
value={username}
/>
<input
name="email"
placeholder="이메일"
onChange={onChange}
value={email}
/>
<button onClick={onCreate}>등록</button>
</div>
);
}
export default CreateUser;
이 글은 패스트캠퍼스 '프론트엔드(React)올인원패키지Online'을 수강하며 정리한 노트입니다.
https://fastcampus.co.kr/search?keyword=%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C