React/Velopert's React

[React] Study #17 | useCallback

yevdev 2021. 10. 8. 11:07

💡useCallback

  • useCallback은 useMemo와 비슷한 Hook
  • useMemo는 특정 결과값을 재사용
  • useCallback은 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용

 

이전에 App.js 에서 구현했던 onCreate, onRemove, onToggle 함수를 확인해보자

const onCreate = () => {
  const user = {
    id: nextId.current,
    username,
    email
  };
  setUsers(users.concat(user));

  setInputs({
    username: '',
    email: ''
  });
  nextId.current += 1;
};

const onRemove = id => {
  // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
  // = user.id 가 id 인 것을 제거함
  setUsers(users.filter(user => user.id !== id));
};
const onToggle = id => {
  setUsers(
    users.map(user =>
      user.id === id ? { ...user, active: !user.active } : user
    )
  );
};
  • 이 함수들은 컴포넌트가 리렌더링 될 때마다 새로 만들어진다.
  • 사실, 함수를 선언하는 것 자체는 사실 메모리도, CPU도 리소스를 많이 차지 하는 작업은 아니기 때문에 함수를 새로 선언한다고 해서 그 자체만으로 큰 후가하 생길 일은 없지만, 함수를 필요할 때만 만들고 재사용하는 것은 여전히 중요하다.
  • 나중에 컴포넌트에서 props가 바뀌지 않았으면 Virtual DOM에 새로 렌더링 하는 것 조차 하지 않고 컴포넌트의 결과물을 재사용하는 최적화 작업을 하려면 함수를 재사용하는 것이 필수이다!

 

useCallback을 사용해보자!

App.js

import React,{useRef, useState, useMemo, useCallback} from 'react'; // useCallback 불러오기
import UserList from './UserList';
import CreateUser from './CreateUser';

function countActiveUsers(users){
  console.log('활성 사용자 수를 세는 중...');
  return users.filter(user => user.active).length;
}

function App() {

  const [inputs, setInputs] = useState({
    username: '', email: ''
  })


  const {username, email} = inputs;

  // useCallback으로 함수 재사용
  const onChange = useCallback ( e => {
    const {name, value} = e.target;
    setInputs({
      ...inputs,
      [name]: value
    })
  }, [inputs]
  );


  const [users, setUsers] = useState(
    [
      {id: 1, username: 'John', email: 'john@example.com',
      active: true,
    },
      {id: 2, username: 'Car', email: 'car@example.com',
      active: false,
    },
      {id: 3, username: 'lee', email: 'lee@example.com',
      active: false,
    },
    ]
)
    

const nextId = useRef(4);

// useCallback으로 함수 재사용
const onCreate = useCallback(() => {

    const user = {
      id: nextId.current,
      username,
      email
    };
    setUsers(users.concat(user));

    setInputs({
      username: '',
      email: ''
    })
    nextId.current += 1;
},[users, username, email]);

// useCallback으로 함수 재사용
const onRemove = useCallback(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])

// useMemo 사용
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;

🚫 주의! 함수안에서 사용하는 상태 혹은 props가 있다면 꼭, deps 배열안에 포함시켜야 된다는 것이다.

  • 값을 넣지 않게 된다면, 함수 내에서 해당 값을 참조할 때 가장 최신 값을 참조할 것이라고 보장 할 수 없다!

 

 


Reference

https://react.vlpt.us/basic/18-useCallback.html