Post

리액트 클로저란 무엇일까??

클로저(Closures)란?

“클로저(closures)“는 자바스크립트의 중요한 개념 중 하나입니다. 클로저는 함수와 그 함수가 선언될 때의 렉시컬 환경(lexical environment)과의 조합을 말합니다. 쉽게 말해, 어떤 함수 내부에서 선언된 내부 함수가 외부 함수의 변수에 접근할 수 있는 기능을 의미합니다. 리액트에서 클로저는 주로 함수형 컴포넌트와 훅에서 발생하는 특정 문제들을 이해하거나 해결할 때 중요한 역할을 합니다.

리액트에서의 클로저 문제

리액트에서 클로저가 중요한 역할을 하는 상황 중 하나는 useState나 useEffect 같은 훅을 사용할 때입니다. 특히 useEffect 내부에서 상태나 props에 접근할 때, 클로저로 인해 발생하는 문제를 이해할 필요가 있습니다.예를 들어, useEffect 훅은 컴포넌트가 렌더링될 때 정의된 상태의 스냅샷을 “캡처”합니다. 만약 상태가 업데이트되어도, 이미 생성된 useEffect 함수는 초기 렌더링 시의 상태를 “기억”하고 있기 때문에, 최신 상태를 반영하지 못하는 문제가 발생할 수 있습니다. 이는 클로저가 해당 스코프의 변수들을 참조하고 있기 때문입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { useState, useEffect } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      console.log(count); // 항상 0을 출력함
    }, 1000);

    return () => clearInterval(interval);
  }, []); // 의존성 배열이 비어 있기 때문에, count가 항상 0으로 캡처됨

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

위 예제에서 setInterval 콜백 함수는 count의 초기 값을 계속 참조합니다. 이는 useEffect가 처음 실행될 때의 count 값(0)을 클로저를 통해 “캡처”하기 때문입니다. 이 문제를 해결하기 위해선 의존성 배열에 count를 추가하거나, 함수형 업데이트를 사용해야 합니다.

클로저 이해의 중요성

클로저를 이해하고 있으면, 리액트의 함수형 컴포넌트에서 발생할 수 있는 여러 문제들을 예방하거나 해결하는 데 도움이 됩니다. 특히, 상태 업데이트 로직을 구현할 때 클로저로 인해 예상치 못한 오류가 발생하지 않도록 주의해야 합니다. 이는 리액트에서 상태 관리를 보다 효과적으로 할 수 있게 도와줍니다.

클로저와 상태 업데이트

리액트에서 useState와 같은 훅을 사용할 때, 클로저는 종종 “스테일 상태(stale state)” 문제를 발생시킵니다. 이는 useEffect와 같은 훅 내부에서 설정된 상태가 외부 스코프의 최신 상태를 반영하지 않는 현상입니다. 이 문제를 해결하기 위한 몇 가지 방법이 있습니다:

1. 의존성 배열 사용: useEffect나 useCallback 훅의 의존성 배열에 상태 변수를 포함시키면, 해당 변수가 변경될 때마다 훅이 다시 실행되어 최신 상태를 반영합니다.

1
2
3
4
5
6
7
useEffect(() => {
  const interval = setInterval(() => {
    console.log(count);
  }, 1000);

  return () => clearInterval(interval);
}, [count]);  // count가 변경될 때마다 useEffect가 다시 실행됩니다.

2. 함수형 업데이트: 상태 업데이트 함수에 함수를 전달하여 현재 상태에 기반한 업데이트를 수행할 수 있습니다. 이 방식은 클로저 문제를 완전히 피할 수 있습니다.

1
2
3
4
// count 상태를 업데이트하는 버튼 클릭 핸들러
<button onClick={() => setCount(currentCount => currentCount + 1)}>
  Click me
</button>

다음시간에 계속…

image

This post is licensed under CC BY 4.0 by the author.