Skip to content

21. 정리 — 여기서부터 어디로

This content is not available in your language yet.

대상 독자: 20. 자리에 놓인 값은 누가 처리하나까지 따라온 개발자 목표: 만든 것을 되짚고, 다음에 읽을 곳 고르기

설치부터 핸들러까지 만든 것을 한 줄씩 되짚습니다.


  • 00 pesde와 Rojo로 패키지 셋을 깔고, 편집기와 CI에 타입 검사 플래그를 넣었습니다.
  • 01 설정 모듈 하나에 q를 만들어 두고, 진입점에서 ScreenGui를 띄웠습니다.
  • 02 q.Elem "Frame"으로 카드를 그렸습니다 — 문자 키는 프로퍼티, 숫자 키는 자식, Parent는 밖에서.
  • 03 q.Source와 :Compute로 값이 원천에서 프로퍼티까지 흐르게 했습니다.
  • 04 버튼 이벤트로 원천을 바꿔 카운터를 완결시켰습니다.
  • 05 q.Tag와 q.Attr로 인스턴스에 이름표와 속성을 달아 밖에서 찾을 수 있게 했습니다.
  • 06 반대 방향도 봤습니다 — q.Out으로 엔진이 바꾼 프로퍼티를 다시 Source로 끌어올렸습니다, 왕복인데도 무한히 돌지 않는 이유까지.
  • 07 q.Ref/q.PreRef/q.PostRef로 만들어진 인스턴스를 손에 쥐었습니다 — 언제 채워지는지와 :Unwrap/:Callback/:Wait까지.
  • 08 :Observer로 화면 밖에서 관측하고, q.Effect로 의존성 여럿과 cleanup을 다뤘습니다 — 화면 안쪽은 값으로, 바깥은 Effect로.
  • 09 q.OnCreated/q.OnRendered/q.OnDestroyed로 생성·완성·파괴 한 번씩을 잡았습니다 — 07·08의 재료로 손수 짜 본 뒤 같은 것에 이름을 붙였습니다.
  • 10 반복되는 프로퍼티 묶음을 Modifier 값으로 빼 모듈 하나에 모았습니다.
  • 11 q.Slot으로 별개의 작은 상자에 자식이 들어갈 자리를 잡고 넣고 뺐습니다 — Offset/Length가 따라 움직이는 것과, 자리 하나를 State로 갈아 끼우는 것까지.
  • 12 카운터를 컴포넌트로 쪼개고, 그 Slot을 props로 넘겨받았습니다 — 안에서 만드는 상태와, 체크박스처럼 밖에서 받아 되돌려 쓰는 원천까지.
  • 13 지금까지 써 온 콜백·클로저·팩토리·커링에 이름을 붙이고, 팩토리를 컴포넌트에 넘겨 안쪽 상태에 붙였습니다 — 손으로 만든 Sum은 q.Operator.Sum을 :Apply하는 것으로 줄였습니다.
  • 14 Slot:List로 데이터에 맞춰 목록을 그렸습니다 — 살아남은 키는 재사용, 하나짜리는 :Single.
  • 15 q.Context 가방으로 값을 층을 건너 넘겼습니다 — 중간 컴포넌트는 안에 뭐가 들었는지 모른 채.
  • 16 q.Store로 이름 붙은 Source 여러 개를 한 곳에 모아 15장의 Context 가방에 그대로 실어 보냈습니다.
  • 17 q.Tween과 q.Animate로 값이 부드럽게 넘어가게 했습니다.
  • 18 q.Blocker로 값 여럿을 바꾸는 구간을 묶어 통지 한 번으로 접었습니다.
  • 19 그 모든 자리가 언제 도는지를 한자리에서 대조했습니다.
  • 20 props의 자리마다 누가 값을 맡고 어떻게 놓는지 — State<Tag>·State<Observer?>·State<Instance?>가 한 원리였음을 봤습니다.

여기까지 화면을 띄우기만 했으니 내리는 법도 한 번 적어 둡니다. quad가 만든 값을 버리는 정본 경로는 q.dispose입니다. 루트 하나를 넘기면 됩니다.

-- 새 예시: 별도 스크립트(01장의 진입점에서 만든 screen을 내린다)
q.dispose(screen)

실행하면 그 아래 인스턴스가 전부 함께 파괴되고, 그 인스턴스들의 숫자 키 자리에 매달려 있던 것이 같이 멈춥니다. :Observer는 멈추고, q.Effect와 q.OnDestroyed는 각각 cleanup과 콜백이 한 번 돈 뒤 끝납니다. 08·09장에서 카드 하나로 본 일이 트리 전체에 한꺼번에 일어나는 것입니다. 따로 끊어야 하는 것은 하나뿐입니다. :Subscribe()로 직접 건 강한 구독은 인스턴스와 무관하므로 :Unsubscribe()를 불러 주세요. 그리고 버린 트리는 다시 살릴 수 없으니, 화면을 잠깐 감출 거라면 Enabled = false(또는 Visible = false)로 두고 정말 버릴 때만 내립니다.

inst:Destroy()와 뭐가 다른가요?

결과는 같습니다. q.dispose도 결국 인스턴스를 파괴하고, quad는 인스턴스의 엔진 연결이 끊긴 것으로 죽음을 알아채므로 밖에서 Destroy()해도 위와 똑같이 정리됩니다. 다른 점은 버리면 안 되는 값을 막아 주는지입니다.

  • Slot 안에 있는 원소를 q.dispose에 넘기면 파괴하지 않고 에러를 냅니다 — Quad0179 dispose: this value is still held by a Slot or a mounted position - …. 먼저 :Extract로 자리에서 빼거나(11장), :List라면 데이터에서 그 키를 지우세요. Destroy()는 그 확인 없이 지워서 Slot이 죽은 원소를 든 채로 남습니다.
  • 숫자 키 자리에 지금 놓인 원소 — q.Elem "Frame" { child }의 정적 자식, State<Instance?> 자리에 지금 놓인 원소, UICorner = 8이 만든 관리 자식 — 도 같은 에러로 막힙니다. 먼저 cur:Set(nil)(또는 다른 값)으로 자리에서 내려놓은 뒤 버리세요 — 11장 §6의 cur:SetAndDispose(nil)이 이 두 단계를 이 순서로 한 번에 합니다. 11장 §6에서 갈아 끼워 떼어진 옛 원소는 이미 내려와 있으니 바로 q.dispose하면 됩니다.
  • 루트처럼 어디에도 놓이지 않은 값은 둘 중 무엇을 써도 같습니다. 그래도 q.dispose로 통일해 두면, 나중에 그 값이 어딘가에 놓이게 됐을 때 실수를 에러로 잡습니다.

  • 실전 레시피 — 재사용 가능한 컴포넌트를 만들 때의 경계 규약이 첫 장입니다. 이어서 폼 검증, 긴 목록, 외부 신호 브릿지, 테마, 헤드리스 테스트, Studio 템플릿 Claim, v1 이관, 그리고 부록인 에러 읽는 법이 있습니다.
  • API 레퍼런스 — 타입당 한 페이지. 시그니처·인자·에러 문구를 찾을 때. 시작하기에 안 나온 것 중 먼저 볼 만한 것은 컴포넌트 하나가 던져도 화면 조립이 멈추지 않게 하는 Fallback / Traceback입니다. Store는 16장에서 이미 봤지만, :Of·예약 키까지 전체 표면이 궁금하면 여기로.
  • The Quadnomicon — 위의 동작들이 내부에서 어떻게 구현돼 있는지. 초보자용은 아닙니다.
  • 왜 Quad인가 — 이 설계가 무엇을 포기하고 무엇을 얻었는지, 다른 도구와의 차이.

quad v1(Quad.Init(id) / Class "Frame")을 쓰던 분이라면 걸리는 자리가 몇 군데 정해져 있습니다.

v1을 쓰던 손버릇 중에 뭐가 안 통하나요?

v1을 쓰던 분이 가장 자주 넘어지는 자리들입니다. 큰 그림(무엇이 왜 없어졌고 어떤 틀로 옮기는지)은 quad v1에서 오는 분께, 전체 이관 절차는 08. quad v1에서 v2로 옮기기에 있습니다.

  • v2에는 :With가 없습니다 — v1의 파생(register:With(fn))은 v2에서 :Compute(fn, ...deps)입니다. 구독만 넓히는 v2의 :Depend(...)는 파생이 아니니 이름을 바꿔 옮기는 자리가 아닙니다.
  • Mount(parent, obj)는 없습니다 — 만들어진 뒤 obj.Parent = parent.
  • 이벤트는 문자 키에, self는 오지 않습니다 — [Event "Activated"] = fn(self, …) → Activated = fn(…).
  • Class.Extend()는 없습니다 — 컴포넌트는 props를 받아 인스턴스를 돌려주는 평범한 함수입니다.
  • **myStore "key"는 store.key**입니다 — 문자열 레지스터가 아니라 그 자리에 넣은 Source 그 자체입니다.
  • id로 찾아오는 창구가 없습니다 — Frame "id" {} / Store.GetObject(id)는 폐지됐고, Ref는 그 대체재가 아닙니다.
  • Style은 Modifier이고 숫자 키 자리에 놓입니다 — 이름 매칭이 아니라 놓인 순서가 우선순위입니다.