Files
2nd/10_Wiki/Topic_Programming/Frontend/One-way_Data_Flow.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

5.9 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-one-way-data-flow One-way Data Flow 10_Wiki/Topics verified self
One-way Data Flow
Unidirectional Data Flow
Top-down Props
none A 0.9 applied
react
frontend
architecture
data-flow
state-management
2026-05-10 pending
language framework
TypeScript React

One-way Data Flow

매 한 줄

"매 state 매 down, event 매 up". Unidirectional data flow 매 React (Flux 영감) 의 core mental model — parent props 으로 child 에 데이터 전달, child callback 으로 parent 에 event 통보. 매 reasoning 의 단순화, debugging 의 traceability, time-travel 의 가능성. Vue/Solid/Svelte 도 매 동일 원칙.

매 핵심

매 핵심 규칙

  • State 매 single owner (component or store).
  • Owner 만 mutate 가능.
  • Child 매 read-only props 만 받음.
  • Child 의 변경 요청 매 callback / event / dispatch.

매 왜 unidirectional

  • Predictability: state 변경 source 매 명확.
  • Debugging: render output 매 props 의 함수.
  • Time-travel: state snapshot 만 으로 UI 재현.
  • Concurrency: 매 React Concurrent 매 mutable 2-way 매 deadlock-prone.

매 응용

  1. React props/callback 패턴.
  2. Redux / Zustand / Jotai store dispatch.
  3. Vue props down, emit up.
  4. Form: lift state up.
  5. Event sourcing / CQRS frontend.

💻 패턴

Lifting state up (React)

function Parent() {
  const [name, setName] = useState("");
  return (
    <>
      <NameInput value={name} onChange={setName} />
      <Greeting name={name} />
    </>
  );
}

function NameInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {
  return <input value={value} onChange={(e) => onChange(e.target.value)} />;
}

function Greeting({ name }: { name: string }) {
  return <p>Hello, {name || "stranger"}!</p>;
}

Reducer (action up, state down)

type Action = { type: "add"; item: string } | { type: "remove"; idx: number };
type State = { items: string[] };

function reducer(s: State, a: Action): State {
  switch (a.type) {
    case "add": return { items: [...s.items, a.item] };
    case "remove": return { items: s.items.filter((_, i) => i !== a.idx) };
  }
}

function TodoApp() {
  const [state, dispatch] = useReducer(reducer, { items: [] });
  return (
    <>
      <AddBox onAdd={(item) => dispatch({ type: "add", item })} />
      <List items={state.items} onRemove={(idx) => dispatch({ type: "remove", idx })} />
    </>
  );
}

Zustand (store as single source)

import { create } from "zustand";

interface CartStore {
  items: { id: string; qty: number }[];
  add: (id: string) => void;
  remove: (id: string) => void;
}

export const useCart = create<CartStore>((set) => ({
  items: [],
  add: (id) => set((s) => ({ items: [...s.items, { id, qty: 1 }] })),
  remove: (id) => set((s) => ({ items: s.items.filter((i) => i.id !== id) })),
}));

function ProductCard({ id }: { id: string }) {
  const add = useCart((s) => s.add);
  return <button onClick={() => add(id)}>Add</button>;
}

Vue 3 props down + emit up

<!-- Parent.vue -->
<template>
  <Counter :value="count" @increment="count++" />
</template>
<script setup>
import { ref } from "vue";
const count = ref(0);
</script>

<!-- Counter.vue -->
<template>
  <button @click="$emit('increment')">{{ value }}</button>
</template>
<script setup>
defineProps<{ value: number }>();
defineEmits<{ increment: [] }>();
</script>

Server-driven (React Query + URL state)

import { useQuery } from "@tanstack/react-query";
import { useSearchParams } from "react-router";

function ProductList() {
  const [params, setParams] = useSearchParams();
  const category = params.get("category") ?? "all";
  const { data } = useQuery({
    queryKey: ["products", category],
    queryFn: () => fetch(`/api/products?cat=${category}`).then((r) => r.json()),
  });
  return (
    <>
      <CategoryPicker value={category} onChange={(v) => setParams({ category: v })} />
      {data?.map((p) => <Card key={p.id} product={p} />)}
    </>
  );
}

Forbidden 2-way leak (anti-pattern shown)

// ❌ child mutates parent's prop directly via mutable ref
function BadChild({ obj }: { obj: { count: number } }) {
  return <button onClick={() => obj.count++}>+</button>; // parent never re-renders
}

매 결정 기준

상황 Approach
2-3 components share state Lift state up
Cross-tree state Context / Zustand / Redux
Server data React Query / SWR (single source)
URL state useSearchParams / Next router
Form-heavy local useReducer + dispatch
Vue props + emit (or Pinia)

기본값: state 매 highest common ancestor 또는 매 store. 매 props down + callback up.

🔗 Graph

🤖 LLM 활용

언제: React/Vue/Solid component design, form lifting, store architecture. 언제 X: 매 highly local input (e.g. simple text field) — 매 controlled-input over-engineering 회피, uncontrolled OK.

안티패턴

  • Mutate props in child: 매 silent re-render miss.
  • Shared mutable ref: 매 React diff 의 invariant 위반.
  • Two-way binding in big tree: 매 cycle / cascade.
  • Prop drilling 10층: 매 Context / store 으로 cut.
  • Local form state in 매 sync 매 server: 매 stale conflict — server 매 source of truth + optimistic update.

🧪 검증 / 중복

  • Verified (React docs — Sharing State Between Components, Vue docs — Component Basics, Redux principles).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — lifting/reducer/Zustand/Vue emit/server-driven 패턴