공유 자원을 쓰는 사용자 수를 세어, 수가 0에서 1이 될 때 자원을 준비하고 1에서 0이 될 때 정리하는 기법. 사무실에 처음 들어온 사람이 불을 켜고, 마지막에 나가는 사람이 끄는 규칙과 같다.
let lockCount = 0
export function lockScroll() {
if (lockCount++ === 0) document.body.style.overflow = 'hidden' // 0→1일 때만
}
export function unlockScroll() {
if (--lockCount === 0) document.body.style.overflow = '' // 1→0일 때만
}모달 위에 시트가 하나 더 열렸다 닫히는 경우를 생각해 보면 필요성이 보인다. 카운트 없이 "닫히면 스크롤 잠금 해제"로 짜면, 시트가 닫히는 순간 아직 열려 있는 모달 뒤에서 페이지가 스크롤된다. 카운트를 두면 마지막 하나가 닫힐 때만 풀린다. React Portal로 띄운 오버레이들이 겹칠 때 흔히 만나는 문제이고, 증감은 Effect의 설정·정리 함수에 짝지어 둔다(useEffect와 useLayoutEffect).
다른 곳에서의 쓰임
- 메모리 관리: 파이썬(CPython)과 Swift는 객체를 가리키는 참조 수가 0이 되면 바로 해제한다. C++의
shared_ptr도 같다 - 운영체제: 파일 핸들은 모든 프로세스가 닫아야 실제로 닫힌다
- 한계: 서로를 가리키는 순환 참조(Reference Cycle)는 수가 0이 되지 않아 해제되지 않는다. 그래서 CPython은 순환을 찾는 별도 GC(Garbage Collector)를 함께 쓴다
증감이 짝을 이루지 않으면(정리 누락, 중복 해제) 바로 버그가 되므로, 획득과 해제를 한 함수나 한 Effect 안에 묶어 두는 것이 요령이다. 구독을 등록하고 해제하는 옵저버 패턴과 비슷한 주의가 필요하다.