JS Library/React

useCallback 를 사용하여 함수 재사용

원2 2022. 5. 25. 10:20
728x90
반응형

useCallback 은 useMemo 와 비슷한 Hook

 

useMemo 는 특정 결과 값을 재사용 할 때 사용

useCallback 은 특정 함수를 새로 만들지 않고 재사용 할 때 사용

 

 

아래의 함수는 컴포넌트가 리렌더링 될 때 마다 새로 만들어짐

솔직히 함수를 선언하는것 자체는 메모리, CPU, 리소스도 많이 차지 하지 않아서 딱히 신경 안써줘도 되긴 하지만

한번 만든 함수를 필요할때만 새로 만들고 재사용하는 것은 중요함.

 

나중에 컴포넌트에서 props 가 바뀌지 않으면 Virtual DOM 에 새로 렌더링 하는것 조차 하지 않고 컴포넌트의 결과물을 재사용하는 최적화 작업을 할텐데 그 작업을 하려면 함수를 재사용 하는것이 필수

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
    )
  );
};

 


useCallback 함수 사용법

 

App.js

 

import React, {useCallback, useMemo, useRef, useState} from 'react';
import CreateUser from './components/CreateUser';
import UserList from "./components/UserList";

function App() {

    function countActiveUsers(users) {
        console.log("active 값이 ture 인 유저의 수를 센는중...");
        return users.filter(user => user.active).length;
    }


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

    const {username, email} = inputs;

    const onChange = e => {
      const { name, value } = e.target;
      setInputs({
          // spread
          ...inputs,
          [name]: value
      });
    };

    // useState 를 사용하여 컴포넌트의 상태로 관리
    const [users, setUsers] = useState([
        {
            id: 1,
            username: 'velopert',
            email: 'public.velopert@gmail.com',
            active: true
        },
        {
            id: 2,
            username: 'tester',
            email: 'tester@example.com',
            active: false
        },
        {
            id: 3,
            username: 'liz',
            email: 'liz@example.com',
            active: false
        }
    ]);


    const nextId = useRef(4);
    const onCreate = useCallback(() => {
        const user = {
            id: nextId.current,
            username,
            email
        };
        // concat 함수
        setUsers(users.concat(user));

        // spread 함수
        // setUsers([
        //     //spread 문법
        //     ...users,user
        // ]);

        setInputs({
            username: '',
            email: ''
        });

        nextId.current += 1;
    }, [users, username, email]);

    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;

 

여기서 주의 할 점은 함수 안에서 사용하는 상태 혹은 props 가 있다면 꼭 deps 배열안에 포함 시켜야함

안넣으면 함수 내에서 해당 값들을 참조할 때 가장 최신 값을 참조 할 것이라고 보장이 안됨

props 로 받아온 함수가 있으면 그것도 deps 배열에 넣어야함

 

useCallback 은 useMemo 기반으로 만들어져서 아래의 식으로도 표현 가능

 

const exFuntion = useMemo(
    () => () => {
    // 함수안의 내용    
    // 함수안의 내용    
    },
    [users]
);

 

 

728x90
반응형