bkdragon's log

클로저와 useState 본문

React

클로저와 useState

bkdragon 2023. 7. 10. 23:01

클로저의 의미

클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경과의 조합이다.

 

이 말을 이해하려면 실행 컨텍스트에 대해 알아야 한다. 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아둔 객체로 선언된 변수와 함수 this 등의 정보가 담겨있다. 렉시컬 환경은 함수 내의 변수 상태를 관리하는 역할을 한다. 렉시컬 환경은 두부분으로 나뉘여 있는데 로컬 변수를 저장하는 부분과 외부 렉시컬 환경에 대한 참조 부분이다. 우리가 함수 내부에서 전역 변수를 사용할 수 있었던 것도 그 함수의 렉시컬 환경이 외부 렉시컬 환경을 참조하고 있기 때문에 변수 정보를 알고 있어서 그런 것이였다. 다시 클로저의 개념으로 돌아가면

 

함수가 선언됐을 때의 렉시컬 환경, 즉  함수 내부의 지역 변수를 활용한 개념이라고 생각할 수 있다. 클로저의 정의를 이해하기 위해 검색하다보면 다양한 문장을 볼 수 있는데 나에게 가장 와 닿았던 정의 바로 이 문장이다.

 

"이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수를 말한다." 

 

활용 사례를 보며 정의를 이해해보자.

 

클로저 활용 사례

 

1. 접근 권한 제어

const counter = () => {
        let count = 0;

        return {
            get : () => {
                    return count;
            },
            up : (number : number) => {
                    count += number;
                    return count;
            }
     }
}

이렇게 하면 count 변수 자체는 외부에서 직접 접근할 수 없다. get을 통해 값을 얻거나 up을 통해 값을 올리는 동작은 가능하다.

 

 

즉시 실행 함수와 함께 사용하면 전역 변수 사용 억제 효과를 얻을 수 있다.

const button = document.getElementById('inclease');
const count = document.getElementById('count');  // 0

const counter = (() => {
        let count = 0;

        return {
            get : () => {
                    return count;
            },
            up : (number : number) => {
                    count += number;
                    return count;
            }
     }
})();

button.onClick = function () {
    count.innerHTML = counter.up(1)
}

클로저인 counter 함수를 즉시 실행했다. 즉시 실행 함수는 한번만 실행되기 때문에 내부 변수 count가 초기회 되지 않고 up을 호출 할 때마다 늘어나게 된다.

 

 

또한 count 변수는 private한 변수이기 때문에 의도치 않은 변경을 걱정할 필요가 없다.

 

 

2. 디바운스

프론트엔드에서 많이 쓰이는 기법인 디바운스이다.

function getDebounce (callback : (...arg : any[]) => void, timeout : number = 1000) {
    let timer : any = null;
    return (...args : any[]) => {
            if(timer) {
                clearTimeout(timer)
            }

            timer = setTimeout(() => {
                    callback(...args)
            }, timeout)
    }
}

   

 

2.  커링

커링은 인자를 순처적으로 받아 마지막에 인자까지 받으면 원하는 동작을 실행시키는 함수이다.

각 단계에서 넘겨받은 인자들은 모두 마지막에 참조될 것이다.

const curry5 = func => a => b => c => d => e => func(a, b, c, d, e);

 

개념이 잡히는가? 길게 풀어서 설명하면 어떤 함수 A에서 선언한 변수 a를 참조하는 내부 함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상이라고 할 수 있겠다.

 

클로저와 useState

클로저의 개념을 익히고 예시를 공부하다보니 useState가 클로저가 아닌가 하는 생각이 들었다.

const [count, setCount] = useState<number>(0);

 

useState는 변수와 변수를 변경할 수 있는 함수를 제공해준다.

const useState = <T extends any>(initialState : T) => {
        let state = initialState;

        const setState = (value : T) => {
                state = value;
        }

        return [state, setState]
}

자세하게 비교하면 다르겠지만(컴포넌트의 리렌더링을 유발하는 등의 동작) useState의 내부은 이런식이지 않을까란 생각이 든다.

 

 

어찌됐던 클로저이다.

 

커스텀 훅을 제작하는 방식도 이런 식이니 클로저의 개념을 모르고 있었다면  모르고도 잘 활용하고 있었을 수 있다. 아는 만큼  보인다!

'React' 카테고리의 다른 글

반복되는 요소 렌더링 최적화 하기  (0) 2023.08.05
React 이벤트 위임  (0) 2023.07.30
[React] 성능 최적화  (0) 2023.06.29
[React] Virtual DOM  (0) 2023.06.25
[React Query] Mutation 이후 캐시 데이터 직접 변경하기  (0) 2023.06.24