컴포넌트 최적화(2) - useCallback()

김재한·2023년 2월 12일
0

React 기초

목록 보기
3/9

useCallback을 사용해 불필요한 리렌더링 방지

컴포넌트가 렌더링 될 때 내부에 있는 함수들도 다시 만들어지게 된다. 똑같은 함수를 렌더링 될 때 마다 새로 만드는 것은 좋은 현상은 아니며 해당 함수를 자식 컴포넌트에게 props로 전달할 경우, 새로운 props로 인식하고 리렌더링이 발생한다. 오늘은 useCallback()을 사용해 컴포넌트를 최적화 하는 방법을 정리해 보려고 한다.

[ 문제의 상황 ]

[app.js]

import './App.css';
import {useState} from "react";
import Lists from "./components/Lists";
import Form from "./components/Form";

function App() {
  console.log('App.js Rendering')
  const [todoData,setTodoData] = useState([])
  const [inputValue, setInputValue] = useState('')
  const handleSubmit = (e) =>{
    e.preventDefault()
    let newTodo ={
      id: Date.now(),
      title: inputValue,
      completed: false
    }
    setTodoData([...todoData,newTodo])
    setInputValue('')
  }
	// useCallback() 적용 대상
  const handleClick = (id) => {
    let newTodoData = todoData.filter((data) => data.id !== id);
    setTodoData(newTodoData);
    localStorage.setItem('todoData', JSON.stringify(newTodoData));
  };

  return (
    <div className="flex items-center justify-center w-screen h-screen bg-blue-100  ">
      <div className="w-full p-6 m-4 bg-white rounded shadow lg:w-3/4 lg:max-w-lg">
        <div  className="flex justify-between mb-3">
          <h1>할 일 목록</h1>
        </div>
        <Lists todoData={todoData} setTodoData={setTodoData} handleClick={handleClick}/>
        <Form handleSubmit={handleSubmit} inputValue={inputValue} setInputValue={setInputValue} />
      </div>
    </div>
  );
}

export default App;
1. Todo 앱에서 해야할 일을 입력만 하는데도 Lists, List 컴포넌트가 리렌더링 된다.

	원인: app.js가 리렌더링 되면서 handleClick 함수가 새로 만들어져 리렌더링이 발생한 것.

자식 컴포넌트에서 React.memo를 사용해 1차 최적화를 시켰지만 렌더링 시 부모 컴포넌트의 함수가 새로 생성되는 것은 어쩔 수 없으므로 리렌더링이 발생했다.

1. useCallback() 사용법

// 변경 전
const myFunction = (param) => {
  ~~~~
};

-> 
// 변경 후
const myFunction = useCallback((param) => {
  ~~~
},[]);
1. 함수 내에서 참조하는 state, props 가 있다면 의존성 배열에 추가해 주면 된다.
2. useCallback() 으로 인해 의존성 배열 데이터들이 변하지 않는다면 함수를 새로 생성하지 않는다.
3. 의존성 배열에 아무것도 없다면, 최초 렌더링 시에만 함수가 생성되고 이후부터는 동일한 참조 값을 사용하는 함수가 된다.

2. 적용해보기

[app.js]

import './App.css';
import {useState} from "react";
import Lists from "./components/Lists";
import Form from "./components/Form";

function App() {
  console.log('App.js Rendering')
  const [todoData,setTodoData] = useState([])
  const [inputValue, setInputValue] = useState('')
  const handleSubmit = (e) =>{
    e.preventDefault()
    let newTodo ={
      id: Date.now(),
      title: inputValue,
      completed: false
    }
    setTodoData([...todoData,newTodo])
    setInputValue('')
  }
  // useCallback 적용 후
  const handleClick = useCallback((id) => {
    let newTodoData = todoData.filter((data) => data.id !== id);
    setTodoData(newTodoData);
    localStorage.setItem('todoData', JSON.stringify(newTodoData));
  },[todoData]);

  return (
    <div className="flex items-center justify-center w-screen h-screen bg-blue-100  ">
      <div className="w-full p-6 m-4 bg-white rounded shadow lg:w-3/4 lg:max-w-lg">
        <div  className="flex justify-between mb-3">
          <h1>할 일 목록</h1>
        </div>
        <Lists todoData={todoData} setTodoData={setTodoData} handleClick={handleClick}/>
        <Form handleSubmit={handleSubmit} inputValue={inputValue} setInputValue={setInputValue} />
      </div>
    </div>
  );
}

export default App;


실제 리렌더링이 필요한 app 과 Form 컴포넌트만 리렌더링 되는 것을 확인할 수 있다.

0개의 댓글