JS

[JS] ν΄λ‘œμ €(Closures)와 λ¦¬μ•‘νŠΈμ˜ ν›…(useState)의 관계

hyonie 2025. 1. 19. 20:28

 

ν΄λ‘œμ €λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ μ€‘μš”ν•œ κ°œλ…μœΌλ‘œ μ™ΈλΆ€μ—μ„œ μ ‘κ·Όν•  수 μ—†λŠ” λΉ„κ³΅κ°œ λ³€μˆ˜λ₯Ό 생성해 데이터 은닉을 κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€. λ˜ν•œ, 비동기 μž‘μ—…μ΄λ‚˜ 이벀트 ν•Έλ“€λŸ¬μ—μ„œ μƒνƒœλ₯Ό 효과적으둜 μœ μ§€ν•˜λ©° ν™œμš©ν•  수 μžˆμ–΄ μœ μš©ν•©λ‹ˆλ‹€.

 

이 κΈ€μ—μ„œλŠ” ν΄λ‘œμ €μ˜ μž₯점 그리고 이λ₯Ό ν™œμš©ν•΄ μ½”λ“œμ˜ μž¬μ‚¬μš©μ„±μ„ λ†’μ΄λŠ” 방법과 μΆ”κ°€λ‘œ, React의 μƒνƒœκ΄€λ¦¬ useState와 ν΄λ‘œμ €μ˜ 관계에 λŒ€ν•΄μ„œλ„ μ •λ¦¬ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

 

πŸ“‚ λͺ©μ°¨

     


    1. ν΄λ‘œμ €λž€ λ¬΄μ—‡μΌκΉŒβ“

    ν΄λ‘œμ €λŠ” λ‚΄λΆ€ ν•¨μˆ˜κ°€ μ™ΈλΆ€ ν•¨μˆ˜μ˜ λ³€μˆ˜(λ ‰μ‹œμ»¬ ν™˜κ²½)에 μ ‘κ·Όν•  수 μžˆλŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. 

    이둜 인해 ν•¨μˆ˜κ°€ 호좜된 이후에도 μ™ΈλΆ€ ν•¨μˆ˜μ˜ μƒνƒœ(λ³€μˆ˜)λ₯Ό μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    • ν΄λ‘œμ €λŠ” μ™ΈλΆ€ λ³€μˆ˜ κ°’ μƒνƒœλ₯Ό ν•¨μˆ˜ 호좜 이후에도 μœ μ§€ν•©λ‹ˆλ‹€.
    • 이 μƒνƒœλŠ” μ™ΈλΆ€μ—μ„œ 직접 μ ‘κ·Όν•  수 μ—†κ³ , λ‚΄λΆ€ ν•¨μˆ˜λ‘œλ§Œ 접근이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

     

    2. ν΄λ‘œμ € 예제 μ½”λ“œ

    μ•„λž˜λŠ” ν΄λ‘œμ €μ˜ κΈ°λ³Έ λ™μž‘μ„ μ„€λͺ…ν•˜λŠ” 예제 μ½”λ“œμž…λ‹ˆλ‹€. ν•¨μˆ˜κ°€ μ€‘μ²©λ˜μ–΄ μžˆμ„ λ•Œ, λ‚΄λΆ€ ν•¨μˆ˜κ°€ μ™ΈλΆ€ ν•¨μˆ˜μ˜ λ³€μˆ˜μ— μ ‘κ·Όν•˜λŠ” 예λ₯Ό λ³΄μ—¬μ€λ‹ˆλ‹€.

    function outerFunction(){
      let outerVariable = "λ‚˜λŠ” μ™ΈλΆ€ λ³€μˆ˜!";
    
      function innerFunction(){
        console.log(outerVariable); // μ™ΈλΆ€ ν•¨μˆ˜μ˜ λ³€μˆ˜μ— μ ‘κ·Ό
      }
    
      return innerFunction;
    }
    
    const closureFunction = outerFunction();
    
    closureFunction(); // "λ‚˜λŠ” μ™ΈλΆ€ λ³€μˆ˜!" 좜λ ₯

     

    • innerFunction은 outerFunction() λ‚΄λΆ€μ—μ„œ μ„ μ–Έλ˜μ—ˆμœΌλ©°, outerFunction()의 μŠ€μ½”ν”„μ— μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€. 
    • outerFunction()이 μ‹€ν–‰λœ 이후에도, innerFunction()은 μ™ΈλΆ€ λ³€μˆ˜(outerFunction)에 μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό ν΄λ‘œμ €(Closure) 라고 ν•©λ‹ˆλ‹€.

     

    3. ν΄λ‘œμ €λŠ” 어디에 ν™œμš©ν•  수 μžˆμ„κΉŒ?

    ν΄λ‘œμ €λŠ” 주둜 λ‚΄λΆ€ 정보λ₯Ό μ€λ‹‰ν•˜κ±°λ‚˜, μƒνƒœλ₯Ό μœ μ§€ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. μ•„λž˜λŠ” λͺ‡ κ°€μ§€ ν™œμš© 예제 μ½”λ“œ μž…λ‹ˆλ‹€.

     

     

    1️⃣ 데이터 은닉 및 μΊ‘μŠν™”

    ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•˜λ©΄ μ™ΈλΆ€μ—μ„œ μ ‘κ·Όν•  수 μ—†λŠ” λΉ„κ³΅κ°œ λ³€μˆ˜λ₯Ό λ§Œλ“€κ³ , 곡개 ν•¨μˆ˜(public function)λ₯Ό 톡해 λ³€μˆ˜ 값을 μ œμ–΄ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    function createCounter() {
      let count = 0; // λΉ„κ³΅κ°œ λ³€μˆ˜
    
      return {
        increment: function () {
          count++;
          console.log(`ν˜„μž¬ 카운트: ${count}`);
        },
        decrement: function () {
          count--;
          console.log(`ν˜„μž¬ 카운트: ${count}`);
        },
        getCount: function () {
          return count;
        },
      };
    }
    
    const counter = createCounter();
    counter.increment(); // ν˜„μž¬ 카운트: 1
    counter.increment(); // ν˜„μž¬ 카운트: 2
    console.log(counter.getCount()); // 2
    counter.decrement(); // ν˜„μž¬ 카운트: 1

     

    • countλŠ” μ™ΈλΆ€μ—μ„œ 직접 μ ‘κ·Όν•  수 μ—†μŠ΅λ‹ˆλ‹€.
    • increment, decrement, getCount ν•¨μˆ˜λ§Œ 톡해 count 값을 μ‘°μž‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

     

     

     

    2️⃣ μƒνƒœ μœ μ§€

    ν΄λ‘œμ €λŠ” 이벀트 ν•Έλ“€λŸ¬λ‚˜ 비동기 μž‘μ—…μ—μ„œλ„ μƒνƒœλ₯Ό μœ μ§€ν•˜λŠ” 데 μœ μš©ν•©λ‹ˆλ‹€.

    function createBtnHandler(btnId) {
      let clickCount = 0;
    
      return function () {
        clickCount++;
        console.log(`${btnId} 클릭 수: ${clickCount}`);
      };
    }
    
    const btn1Handler = createBtnHandler('btn1');
    const btn2Handler = createBtnHandler('btn2');
    
    btn1Handler(); // btn1 클릭 수: 1
    btn1Handler(); // btn1 클릭 수: 2
    btn2Handler(); // btn2 클릭 수: 1

     

    • 각각의 λ²„νŠΌ ν•Έλ“€λŸ¬λŠ” 독립적인 μƒνƒœ(clickCount)λ₯Ό μœ μ§€ν•©λ‹ˆλ‹€.
    • ν΄λ‘œμ € 덕뢄에 clickCount λ³€μˆ˜λŠ” ν•¨μˆ˜ 호좜 μ‹œλ§ˆλ‹€ 이전 값을 κΈ°μ–΅ν•©λ‹ˆλ‹€.

     

     

     

    3️⃣ once ν•¨μˆ˜ κ΅¬ν˜„

    ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•¨μˆ˜κ°€ ν•œ 번만 μ‹€ν–‰λ˜λ„λ‘ μ œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

     

    function once(fn) {
      let executed = false;
    
      return function (...args) {
        if (!executed) {
          executed = true;
          return fn(...args);
        } else {
          console.log('이미 μ‹€ν–‰λœ ν•¨μˆ˜μž…λ‹ˆλ‹€.');
        }
      };
    }
    
    const initialize = once(() => console.log('μ΄ˆκΈ°ν™” μ™„λ£Œ!'));
    
    initialize(); // μ΄ˆκΈ°ν™” μ™„λ£Œ!
    initialize(); // 이미 μ‹€ν–‰λœ ν•¨μˆ˜μž…λ‹ˆλ‹€.
    • executedλŠ” λ‚΄λΆ€μ—μ„œλ§Œ κ΄€λ¦¬λ˜λŠ” λ³€μˆ˜λ‘œ, ν•¨μˆ˜κ°€ ν•œ 번만 μ‹€ν–‰λ˜λ„λ‘ μ œμ–΄ν•©λ‹ˆλ‹€.

     

    4. Reactμ—μ„œ ν΄λ‘œμ €μ™€ useState의 관계 ⭐

    React의 useStateλŠ” ν΄λ‘œμ €μ˜ νŠΉμ„±μ„ ν™œμš©ν•˜μ—¬ μƒνƒœλ₯Ό μœ μ§€ ν•©λ‹ˆλ‹€.

     

    1. useStateλŠ” ν΄λ‘œμ €λ₯Ό 기반으둜 μƒνƒœμ™€ λ Œλ”λ§μ„ κ΄€λ¦¬ν•©λ‹ˆλ‹€.
      • λ‚΄λΆ€ ν•¨μˆ˜κ°€ λ Œλ”λ§ μ‹œμ μ˜ μƒνƒœ 값을 μΊ‘μ²˜ν•˜λŠ” λ°©μ‹μœΌλ‘œ λ™μž‘ν•©λ‹ˆλ‹€.
    2. λ¦¬μ•‘νŠΈμ˜ μƒνƒœκ΄€λ¦¬μ—μ„œ ν΄λ‘œμ €κ°€ μ€‘μš”ν•œμ΄μœ :
      • μ»΄ν¬λ„ŒνŠΈκ°€ μƒνƒœλ₯Ό μœ μ§€ν•˜κ³ , λ Œλ”λ§ κ°„μ˜ 데이터 뢈일치λ₯Ό λ°©μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    3. μ΅œμ‹  μƒνƒœ 기반 μ—…λ°μ΄νŠΈ:
      • ν΄λ‘œμ €λ‘œ μΈν•œ κ°’ 뢈일치 문제λ₯Ό ν•΄κ²°ν•˜λ €λ©΄, setState의 ν•¨μˆ˜ν˜• μ—…λ°μ΄νŠΈ 방식을 μ‚¬μš©ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.

     

     

    1️⃣ λ Œλ”λ§κ³Ό ν΄λ‘œμ €μ˜ 관계

    λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈκ°€ λ Œλ”λ§λ  λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ λžœλ”λ§ μŠ€μ½”ν”„κ°€ μƒμ„±λ©λ‹ˆλ‹€. μ΄λ•Œ, useStateκ°€ λ°˜ν™˜ν•œ count λ³€μˆ˜λŠ” νŠΉμ • λ Œλ”λ§ μ‹œμ μ˜ 값을 ν΄λ‘œμ €λ‘œ μΊ‘μ²˜ν•©λ‹ˆλ‹€. μ•„λž˜ 예제 μ½”λ“œμž…λ‹ˆλ‹€.

    const { useState } = require('react');
    
    export default function CounterRender() {
      const [count, setCount] = useState(0);
    
      function handleClick() {
        setCount(count + 1); // ν΄λ‘œμ €λ‘œ 캑처된 count κ°’ μ‚¬μš©
        console.log('ν΄λ‘œμ €μ—μ„œ 캑처된 κ°’:', count);
      }
    
      return (
        <>
          <p>Count: {count}</p>
          <button onClick={handleClick}>Increase +</button>
        </>
      );
    }

     

    1. ν΄λ‘œμ € λ™μž‘: handleClick ν•¨μˆ˜λŠ” λ Œλ”λ§ μ‹œμ μ˜ count 값을 ν΄λ‘œμ €λ‘œ μΊ‘μ²˜ν•©λ‹ˆλ‹€. λ”°λΌμ„œ setCountλ₯Ό ν˜ΈμΆœν•΄ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈν•΄λ„, 캑처된 값은 λ³€κ²½λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
    2. μƒνƒœ μ—…λ°μ΄νŠΈ: setCountκ°€ 호좜되면, λ¦¬μ•‘νŠΈλŠ” μ»΄ν¬λ„ŒνŠΈλ₯Ό λ‹€μ‹œ λ Œλ”λ§ν•˜κ³  μƒˆλ‘œμš΄ λ Œλ”λ§ μŠ€μ½”ν”„λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. 이둜 인해 countλŠ” μ—…λ°μ΄νŠΈ 된 μ΅œμ‹  값을 μ°Έμ‘°ν•˜κ²Œ λ©λ‹ˆλ‹€.

     

    2️⃣ μ΅œμ‹  μƒνƒœ κ°’ μ‚¬μš©

     

    useState의 μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈν•  λ•Œ μ΅œμ‹  μƒνƒœλ₯Ό 기반으둜 μž‘μ—…ν•˜λ €λ©΄, μ—…λ°μ΄νŠΈ ν•¨μˆ˜ ν˜•νƒœμ˜ setCountλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

    const { useState } = require('react');
    
    export default function CounterRender() {
      const [count, setCount] = useState(0);
    
      function handleClick() {
        setCount((prevCount) => prevCount + 1); // μ΅œμ‹  μƒνƒœ 값을 기반으둜
        console.log('μ΅œμ‹  κ°’ 기반:', count); // μ—¬μ „νžˆ 이전 κ°’
      }
    
      return (
        <>
          <p>Count: {count}</p>
          <button onClick={handleClick}>Increase +</button>
        </>
      );
    }

     

    • setCount((prevCount) => prevCount +1) λŠ” 이전 μƒνƒœλ₯Ό ν΄λ‘œμ €λ‘œ μΊ‘μ²˜ν•˜κ³ , 이λ₯Ό μ΅œμ‹  κ°’μœΌλ‘œ ν™œμš©ν•©λ‹ˆλ‹€.
    • 이 방식은 비동기 μƒνƒœ μ—…λ°μ΄νŠΈ 및 λ Œλ”λ§ κ°„μ˜ 뢈일치 문제λ₯Ό ν•΄κ²°ν•©λ‹ˆλ‹€.

     

    3️⃣ ν΄λ‘œμ €μ™€ useState 곡톡점과 차이점

     

    ꡬ뢄 JavaScript ν΄λ‘œμ € React useState
    μƒνƒœ μœ μ§€ 방식 ν•¨μˆ˜μ˜ λ ‰μ‹œμ»¬ ν™˜κ²½μ„ 톡해 λ³€μˆ˜ μƒνƒœλ₯Ό μœ μ§€ λ¦¬μ•‘νŠΈ λ‚΄λΆ€μ—μ„œ μƒνƒœλ₯Ό κ΄€λ¦¬ν•˜κ³  μ»΄ν¬λ„ŒνŠΈ λ Œλ”λ§ μ‹œ μ΅œμ‹  κ°’ 제곡
    μ—…λ°μ΄νŠΈ 방식 μ™ΈλΆ€μ—μ„œ λ‚΄λΆ€ ν•¨μˆ˜ ν˜ΈμΆœμ„ 톡해 직접 μƒνƒœλ₯Ό μ‘°μž‘ setState ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈ
    적용 λ²”μœ„ λͺ¨λ“  μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œμ—μ„œ μ‚¬μš© κ°€λŠ₯ λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈ λ‚΄μ—μ„œλ§Œ μ‚¬μš© κ°€λŠ₯
    캑처된 κ°’ ν•¨μˆ˜ μ„ μ–Έ μ‹œμ˜ λ ‰μ‹œμ»¬ ν™˜κ²½μ„ κΈ°μ–΅ λ Œλ”λ§ μ‹œμ μ˜ μƒνƒœ 값을 ν΄λ‘œμ €λ‘œ 캑처

     

     

     ν΄λ‘œμ €λŠ” ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλœ 이후에도 μƒμœ„ μŠ€μ½”ν”„μ˜ λ³€μˆ˜μ— μ ‘κ·Όν•  수 있게 ν•΄μ€λ‹ˆλ‹€. 이λ₯Ό 톡해 데이터 은닉, μƒνƒœ μœ μ§€, μ½”λ“œ μž¬μ‚¬μš© λ“±μ˜ λ‹€μ–‘ν•œ μž₯점을 μ œκ³΅ν•˜λ©°, 효율적인 개발이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

    특히, λ¦¬μ•‘νŠΈμ˜ useState와 같은 μƒνƒœκ΄€λ¦¬μ™€ 이벀트 핸듀링 같은 핡심 κ°œλ…μ„ μ΄ν•΄ν•˜λŠ”λ° μ€‘μš”ν•œ 역할을 ν•©λ‹ˆλ‹€. ν΄λ‘œμ €λ₯Ό 잘 ν™œμš©ν•˜λ©΄ μ•ˆμ •μ μ΄κ³  μœ μ§€λ³΄μˆ˜ν•˜κΈ° μ‰¬μš΄ μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.