front/react

[react] React Hook 4 (useCallback, useMemo)

๋ฐฐ๊ณ ํŒŒ์š” 2026. 1. 7. 11:26
728x90

๐Ÿ“ useCallback

  • callback ํ•จ์ˆ˜๋ฅผ memoize (๋ฉ”๋ชจ์ด์ฆˆ)
  • ํ•จ์ˆ˜ ์ž์ฒด (function object )๋ฅผ ์บ์‹ฑํ•˜๋Š” ํ›….
  • ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ค์ง€ ์•Š๋Š” ๋‹ค๋Š” ๊ฒŒ ํ•ต์‹ฌ.!!
  • ํ•จ์ˆ˜์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•˜๋Š” ๊ฒƒ์€ --> useMemo Hook
  • ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
    • useCallback(callback, dependencies)
    • callback  :: ํ•จ์ˆ˜๋ฅผ ๊ธฐ๋ก.
    • dependencies :: ์ด dependencies ์•ˆ์— ์žˆ๋Š” ๊ฐ’์ด ๋ณ€๋™์ด ๋˜๋ฉด ๊ทธ๋•Œ --> callback ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰.
      • ๋งŒ์•ฝ dependencies ๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด --> ํ•œ๋ฒˆ ๋งŒ๋“ค๊ณ  ๋ฐ”๊พธ์ง€ ์•Š์„๊บผ๋ผ๋Š” ๊ฒƒ.
  • ๋”๋ณด๊ธฐ
    useEffect(() => {
        console.log("same handleClick reference?", prevRef.current === handleClick);
        prevRef.current = handleClick;
    });

    /* 
        useEffect :: ๋ Œ๋”๋ง์ด ๋๋‚œ ํ›„ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ 
        ๊ธฐ๋ณธ์ ์œผ๋กœ : - ์ฒซ ๋ Œ๋”๋ง ํ›„ 1๋ฒˆ ์‹คํ–‰. 
                   - ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•  ๋•Œ ๋งˆ๋‹ค ๋‹ค์‹œ ์‹คํ–‰. 
        ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ์—†์œผ๋‹ˆ๊นŒ --> ๋งค ๋ Œ๋”๋ง ํ›„ ์‹คํ–‰ํ•จ. 

        useRef :: prevRef.current ๋Š” ๋ Œ๋”๋ง์ด ๋ฐ”๋€Œ์–ด๋„ ์œ ์ง€๋˜๋Š” ๊ฐ’. 
        ๊ฐ’์ด ๋ฐ”๋€Œ์–ด๋„ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์Œ. 
        ์—ฌ๊ธฐ์„œ๋Š” --> ์ด์ „ ๋ Œ๋”๋ง์˜ handleClick ํ•จ์ˆ˜ ์ฐธ์กฐ๋ฅผ ์ €์žฅํ•˜๋Š” ์šฉ๋„. 
        
     */
  • ๋”๋ณด๊ธฐ


    import { useState, useCallback, useRef, useEffect } from "react";
    import { createRoot } from "react-dom/client";
    
    function Counter() {
        const [count, setCount] = useState(0);
    
        const handleClick = useCallback( () => {
            setCount(perv => perv +1); // ์ง์ „ ๊ฐ’์„ ์ธ์ž๋กœ ๊ฐ€์ ธ์™€์„œ --> ๊ทธ๊ฑธ 1์„ ์ฆ๊ฐ€ ์‹œํ‚ด.
            // setCount(count + 1 ) // ์ด๊ฑด count state ๊ฐ’์„ 1์„ ์ฆ๊ฐ€ ์‹œํ‚ค๋Š” ๊ฒƒ์ž„.
        }); 
        // ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋นˆ ๋ฐฐ์—ด์ด๋ฉด 
        // --> handleClick ์„ ์ฒ˜์Œ ๋ Œ๋”๋ง ๋  ๋•Œ, ํ•œ๋ฒˆ๋งŒ ์ƒ์„ฑํ•˜๊ณ  ๊ธฐ์–ตํ•˜๊ณ  ์žˆ์„ ๊บผ์ž„.
    
        const prevRef = useRef(handleClick);
    
        useEffect(() => {
            console.log("same handleClick reference?", prevRef.current === handleClick);
            prevRef.current = handleClick;
        });
    /* 
        useEffect :: ๋ Œ๋”๋ง์ด ๋๋‚œ ํ›„ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ 
        ๊ธฐ๋ณธ์ ์œผ๋กœ : - ์ฒซ ๋ Œ๋”๋ง ํ›„ 1๋ฒˆ ์‹คํ–‰. 
                   - ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•  ๋•Œ ๋งˆ๋‹ค ๋‹ค์‹œ ์‹คํ–‰. 
        ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ์—†์œผ๋‹ˆ๊นŒ --> ๋งค ๋ Œ๋”๋ง ํ›„ ์‹คํ–‰ํ•จ. 
    
        useRef :: prevRef.current ๋Š” ๋ Œ๋”๋ง์ด ๋ฐ”๋€Œ์–ด๋„ ์œ ์ง€๋˜๋Š” ๊ฐ’. 
        ๊ฐ’์ด ๋ฐ”๋€Œ์–ด๋„ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์Œ. 
        ์—ฌ๊ธฐ์„œ๋Š” --> ์ด์ „ ๋ Œ๋”๋ง์˜ handleClick ํ•จ์ˆ˜ ์ฐธ์กฐ๋ฅผ ์ €์žฅํ•˜๋Š” ์šฉ๋„. 
        
     */
    
        console.log("component rendering")
    
        return (
            <div>
                <h1>Count : {count}</h1>
                <button onClick={handleClick}>์ฆ๊ฐ€</button>
            </div>
    
        );
    }
    
    createRoot(document.getElementById('react4')).render(<Counter />);


 

 


 

 

๐Ÿ“ useMemo

  • Memoized value ๋ฅผ ๋ฆฌํ„ด,.
  • Memoization ์€ ๊ฐ’์„ ์บ์‹ฑํ•˜๋Š” ๊ฒƒ.
    • --> ์žฌ๊ณ„์‚ฐ์ด ํ•„์š”์—†๊ฒŒ ํ•จ.
  • ๋””ํŽœ๋˜์‹œ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งŒ useMemo Hook์ด ์‹คํ–‰ ๋จ.
    • --> ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋  ์ˆ˜ ์žˆ์Œ.
  •  
  useMemo useCallback
๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์˜ ์ฐจ์ด์ . Memoized ๊ฐ’ ๋ฐ˜ํ™˜ Memoization ํ•จ์ˆ˜ ๋ฐ˜ํ™˜
  •  --------------------------------------------------------------------------------------
  • useMemo ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํ•˜๋ฉด ํ•˜๋‚˜ํ•˜๋‚˜ํ•  ๋•Œ๋งˆ๋‹ค ๋กœ๋”ฉ ์—„์ฒญ ๊ฑธ๋ ธ์Œ... 
    • ๋А๋ฆฐ ์ด์œ ๋Š”  const calculation = expensiveCalculation(count); ๋•Œ๋ฌธ์— ๋А๋ฆฐ๊ฑฐ์ž„.
    • counter ํ˜ธ์ถœํ•  ๋•Œ๋Š” expensiveCalculation(count); ๊ฐ€ ๋ถˆ๋Ÿฌ์ ธ์•ผํ•˜๋Š” ๊ฒŒ ๋งž์ง€๋งŒ, 
    • todo ํ˜ธ์ถœํ•  ๋•Œ๋Š” ์–˜๋ฅผ ๋ถ€๋ฅผ ํ•„์š”๊ฐ€ ์—†์Œ.
    • ๋”๋ณด๊ธฐ
      import { useState, useCallback } from "react";
      import {createRoot} from "react-dom/client";
      
      const expensiveCalculation = (num) => {
          console.log("๊ณ„์‚ฐ์ค‘...");
          for( let i = 0; i < 3000000000; i++ ){
              num += 1;
          }
          return num;
      }
      
      function App() {
          const [count, setCount] = useState(0);
          const [todos, setTodos] = useState([]);
          const calculation = expensiveCalculation(count);
      
          const increment = () => {
              setCount( c => c+1 ); // ์—ฌ๊ธฐ์„œ c ๋Š” ์ง์ „๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๊ทธ๋ƒฅ ๋ณ€์ˆ˜์ž„.
          };
      
          const addTodo = () => {
              setTodos( (t) => { return [...t, "์ƒˆ๋กœ์šด ํ• ์ผ"] });
          };
      
          return (
              
              <div>
                  <div>
                      <h2>๋‚˜์˜ ํ• ์ผ๋“ค without useMemo</h2>
                      {todos.map( (todo, idx) => { 
                          return <p key={idx}>{todo}</p>
                      })}
                      <button onClick={addTodo}>ํ• ์ผ ์ถ”๊ฐ€</button>
                  </div>
                  <hr />
                  <div>
                      Count : {count} <button onClick={increment}> + </button>
                  </div>
              </div>
      
          );
      }
      
      createRoot(document.getElementById('react4')).render(<App />);
  • ---------------------------------------------------------------------------------------
  • useMemo ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•ด๋ด„.
    • ์†๋„์ €ํ•˜์˜ ์š”์ธ์ธ expensiveCalculation ๋ถ€๋ถ„์„ count ๊ฐ’์ด ๋ณ€ํ•  ๋•Œ๋งŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ useMemo๋ฅผ ์‚ฌ์šฉํ•จ.
    • const calculation = useMemo( () => expensiveCalculation(count), [count] );
      // count ๊ฐ’์ด ๋ณ€ํ•  ๋•Œ๋งŒ?? --> expensiveCalculation ๋ฅผ ์‹คํ–‰ํ•˜์ž.
      [count] ๋ถ€๋ถ„์ด --> dependencies ์ž„.!!  
    • ๋”๋ณด๊ธฐ
      import { useState, useCallback, useMemo } from "react";
      import {createRoot} from "react-dom/client";
      
      const expensiveCalculation = (num) => {
          console.log(num + " -- ๊ณ„์‚ฐ์ค‘...");
          for( let i = 0; i < 3000000000; i++ ){
              num += 1;
          }
          return num;
      }
      
      function App() {
          const [count, setCount] = useState(0);
          const [todos, setTodos] = useState([]);
          const calculation = useMemo( () => expensiveCalculation(count), [count] );
          // count ๊ฐ’์ด ๋ณ€ํ•  ๋•Œ๋งŒ?? --> expensiveCalculation ๋ฅผ ์‹คํ–‰ํ•˜์ž.
      
          const increment = () => {
              setCount( c => c+1 ); // ์—ฌ๊ธฐ์„œ c ๋Š” ์ง์ „๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๊ทธ๋ƒฅ ๋ณ€์ˆ˜์ž„.
          };
      
          const addTodo = () => {
              setTodos( (t) => { return [...t, "์ƒˆ๋กœ์šด ํ• ์ผ"] });
          };
      
          return (
              
              <div>
                  <div>
                      <h2>๋‚˜์˜ ํ• ์ผ๋“ค with useMemo</h2>
                      {todos.map( (todo, idx) => { 
                          return <p key={idx}>{todo}</p>
                      })}
                      <button onClick={addTodo}>ํ• ์ผ ์ถ”๊ฐ€</button>
                  </div>
                  <hr />
                  <div>
                      Count : {count} <button onClick={increment}> + </button>
                  </div>
              </div>
      
          );
      }
      
      createRoot(document.getElementById('react4')).render(<App />);
  • --------------------------------------------------------------------------------------

 

๐Ÿ“ ?

  • ใ…‡ใ…‡ 

 

 


์ถœ์ฒ˜ : 

https://www.youtube.com/watch?v=bSqXAP7KLyc&list=PLTb3qGCzYjS2AliTIbz9eAGjZSdEQa3m1&index=43

 

 


๊ฐœ๋ฐœ ๊ณต๋ถ€๋ฅผ ์œ„ํ•œ ๋ธ”๋กœ๊ทธ ์ž…๋‹ˆ๋‹ค. 

์˜ค๋ฅ˜๊ฐ€ ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์„ธ์š”! 

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

728x90

'front > react' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[react] React Router v6.4 ( createBrowerRouter, RouterProvi๏ปฟder)  (0) 2026.01.07
[react] React Hook 5 (Custom Hook)  (0) 2026.01.07
[react] React Hook 3 (useReducer)  (0) 2026.01.07
[react] React Hook 2 (useContext, useRef)  (0) 2026.01.06
[react] React Hooks 1 (useState, useEffect)  (0) 2026.01.04