
리액트의 클래스 컴포넌트에 대한 이해가 자바스크립트의 클래스, 프로토타입, 그리고 this에 달려 있다면, 함수 컴포넌트에 대한 이해는 클로저에 달려 있습니다. 함수 컴포넌트의 구조와 작동 방식, 훅의 원리, 의존성 배열 등 대부분의 기술이 모두 클로저에 의존하고 있기 때문입니다.
클로저는 "함수와 함수가 선언된 어휘적 환경의 조합"이라고 정의됩니다. 어휘적 환경이라는 것은 변수가 코드 내부에서 어디서 선언됐는지를 말하는 것입니다. 이는 호출되는 방식에 따라 동적으로 결정되는 this와는 달리 코드가 작성된 순간에 정적으로 결정됩니다. 클로저는 이러한 어휘적 환경을 조합해 코딩하는 기법입니다.
변수의 유효 범위에 따라 어휘적 환경이 결정되며, 이를 스코프라고 합니다. 자바스크립트에는 여러 가지 스코프가 있습니다.
전역 스코프는 어디서든 접근할 수 있는 변수를 의미합니다.
자바스크립트는 기본적으로 함수 레벨 스코프를 따릅니다. 즉, {} 블록이 스코프 범위를 결정하지 않습니다.
function example() {
if (true) {
var x = 10;
}
console.log(x); // 10
}
example();
위 예제에서 var로 선언된 변수 x는 함수 레벨 스코프를 따르므로, 함수 블록 내 어디서든 접근이 가능합니다.
자바스크립트는 스코프를 일단 가장 가까운 스코프에서 변수가 존재하는지를 먼저 확인합니다. 이러한 사실을 알고 있다면, 특정 변수가 어디에 선언되었는지에 따라 값이 달라질 수 있음을 쉽게 확인할 수 있습니다.
리액트에서 클로저의 원리를 사용하는 대표적인 예가 useState입니다. useState는 함수가 호출되는 컴포넌트 내부의 첫 줄에서 종료되지만, setState는 useState 내부의 최신값을 계속해서 확인할 수 있습니다. 이는 클로저가 useState 내부에서 활용되기 때문입니다. 외부 함수(useState)가 반환한 내부 함수(setState)는 외부 함수(useState)의 호출이 끝났음에도 자신이 선언된 환경(state가 저장된 어딘가)을 기억하기 때문에 계속해서 state 값을 사용할 수 있는 것입니다.
다음 예제는 리액트에서 useState 훅을 사용하는 방법을 보여줍니다.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default Counter;
위 예제에서 useState 훅은 count와 setCount를 반환합니다. increment 함수는 setCount를 호출하여 count 값을 증가시킵니다. 이때, setCount는 자신이 선언된 useState의 어휘적 환경을 기억하고 있으므로 최신의 count 값을 참조할 수 있습니다.
클로저는 함수형 프로그래밍의 중요한 개념으로, 부수 효과가 없고 순수한 함수를 만들기 위해 적극적으로 사용됩니다. 리액트의 함수 컴포넌트와 훅의 원리를 이해하려면 클로저의 개념을 잘 알고 있어야 합니다. 클로저는 어려운 개념처럼 보일 수 있지만, 한 번 이해하면 함수형 프로그래밍을 더 효과적으로 사용할 수 있습니다.
리액트의 함수 컴포넌트에서 클로저를 적절히 활용하면, 코드의 가독성을 높이고 유지보수를 용이하게 할 수 있습니다. 이를 통해 더 안정적이고 효율적인 리액트 애플리케이션을 개발할 수 있을 것입니다.