FEInterview Prep

GitHub Pages

자바스크립트 프록시로 초경량 반응형 상태 관리 구현하기

Proxyset 트랩만으로 "상태 변경 → UI 업데이트" 자동화를 구현하는 패턴. 미디어 폼 예제로 라이브러리 없이 반응성을 만든다.

2025-09-12·7분 읽기
JavaScript
원문 보기 ↗

핵심 요약

구성: ① 원본 상태 객체, ② set 트랩이 정의된 핸들러, ③ new Proxy(state, handler) 로 만든 반응형 객체. 사용처에서 proxy.foo = x 하면 트랩이 발동해 ① 실제 값 갱신, ② 등록된 UI 업데이트 함수들 실행. 추가로 공개 API 함수(addPhoto, setVideo, reorderPhotos)상태 조회 모듈(StateQueries) 로 캡슐화. 장점: 의존성 0, 보일러플레이트 거의 없음, 관심사 분리. 단점: 깊은 객체 nested 변경, 비동기/effect 의존 추적은 라이브러리 수준이 아님.

반응성(reactive)의 본질은 "값이 바뀔 때 부수효과를 자동 실행" 이다. Proxyset 트랩은 이 부수효과를 할당 연산자에 정확히 한 번 끼워 넣는 가장 작은 단위의 후크다. Vue/Mobx/Solid 같은 라이브러리도 같은 원리다.

면접에서 "상태 관리 라이브러리 없이 반응성 어떻게 만들지?" 또는 "Vue 의 ref 는 어떻게 동작하나" 류 질문이 자주 나온다. Proxy set 트랩 한 단락만 정확히 이해해도 Vue 3 의 reactive , signal 라이브러리 의 코어를 같은 메커니즘으로 설명할 수 있다.

학습 포인트

면접 답변으로 연결할 학습 포인트입니다.

`Proxy` 의 `set` 트랩은 "할당 연산자 = 에 끼어드는 후크"

const handler = {
  set(target, prop, value) {
    target[prop] = value;
    triggerUpdates();
    return true;
  },
};
const state = new Proxy(raw, handler);
state.foo = 1; // ← 트랩 발동

set반드시 true 반환(strict mode 에서 오류 방지). 이 한 패턴이 모든 reactive 라이브러리의 코어다.

Proxyset trapReflect.setstrict mode
자주 하는 오해

return true 누락. strict mode 에서 TypeError: 'set' on proxy: trap returned falsish 발생.

공개 API 와 직접 변경의 분리 — 왜 `addPhoto` 같은 함수가 필요한가

// ❌ 호출처에 흩뿌려진 직접 변경
state.photos['1'] = url;
state.mediaType = 'photo';

// ✅ 의도가 드러나는 공개 API
addPhoto(url);

공개 API 가 도메인 액션 을 명시하면 트랩 + 액션 함수만 보면 "상태가 어디서·왜 바뀌나" 를 추적 가능. Redux 의 action 과 같은 역할.

public APIencapsulationaction
자주 하는 오해

Proxy 만 만들고 호출처에서 마음대로 mutate. 결과적으로 디버깅 시 "누가 photos[2] 바꿨지" 를 grep 해야 한다.

한계 — 깊은 nested 변경과 동적 의존성 추적

기본 set 트랩은 얕은(shallow) 트랩만 잡는다. state.photos['1'] = urlphotos 객체에 대한 set 이 아니라 그 안 객체의 '1' 키 set 이라 트랩이 발동하지 않을 수도 있다(아래 reorderPhotos 처럼 photos 자체 재할당이 트리거되는 형태로 우회). 깊은 변경 추적·의존성 자동 추적은 Vue/Mobx 처럼 재귀 Proxy + 의존성 그래프 가 필요하다.

shallow proxydeep reactivitydependency tracking
자주 하는 오해

단순 패턴으로 "리덕스 대체" 라고 단정. 실제론 간단한 폼 상태 수준에 적합하다.

읽는 순서

  1. 1이론

    MDN Proxy 트랩 목록을 훑고, set/get/has/deleteProperty 가 각각 어떤 연산을 가로채는지 표로 정리.

  2. 2구현

    본문 미디어 폼 예제를 직접 작성. nested 변경(state.photos.1 = url) 이 트랩에 잡히는지 확인하고 안 잡히는 케이스를 찾는다.

  3. 3실무

    현재 프로젝트의 작은 폼/모달 상태 한 곳을 골라 라이브러리 없이 이 패턴으로 치환 가능한지 평가. 가능하면 의존성 1개를 없애 본다.

  4. 4설명

    "Vue 3 ref 는 내부적으로 어떻게 동작하나" 를 본 패턴에서 출발해 5분 안에 설명. 기본 Proxy → 재귀 → effect dependency 순으로.

면접 연결 질문

medium`Proxy` 만으로 reactive 시스템을 만들 때 "shallow vs deep" 추적의 차이를 설명해 주세요.
힌트

[감점 답변] "Proxy 가 알아서 다 잡아 준다". [좋은 답변] 기본은 shallowstate.user.name = x 같은 nested set 은 잡히지 않는다. 해법은 get 트랩에서 nested 값을 다시 Proxy 로 감싸 반환 하는 재귀 Proxy. Vue 3 가 이 패턴이다.

hard`Object.defineProperty` 와 `Proxy` 의 reactive 구현 차이를 비교해 주세요.
힌트

[좋은 답변] defineProperty이미 존재하는 키만 가로챔 → 새 키 추가/삭제 불가. Proxy임의 키, 메서드 호출, has/deleteProperty 까지 잡는다. 그래서 Vue 2 → 3 로 옮기면서 Proxy 로 갈아탔다.

easy이 패턴을 쓰면 안 되는 케이스는 무엇이고 그 때 어떤 라이브러리를 권하시겠습니까?
힌트

[좋은 답변] 깊은 nested 상태, 비동기/derived state, 시간여행 디버깅이 필요하면 Zustand/Jotai/Redux Toolkit 권장. 본문 패턴은 간단한 폼/UI 상태 까지.

자기 점검

`set` 트랩이 `return true` 를 빠뜨리면 어떤 문제가 생기는지 한 줄로.
strict modeTypeErrortrap returned falsish
자주 하는 오해

"별일 없다" — 실제론 strict mode 에서 throw 한다.

이 패턴이 Vue 3 의 reactive 와 어떻게 닮았고 어떻게 다른지 한 문장으로 비교해 보세요.
recursive Proxydependency trackingeffect
자주 하는 오해

"동일하다" — Vue 3 는 재귀 Proxy + 자동 의존성 추적 이라는 두 단계가 더 있다.