CAKE20

AI Web PaaS

Store

내장 store로 전역 UI 상태를 공유합니다.

파일형 내장 Store

  • app/stores/<이름>.store.ts의 default export 객체가 같은 이름의 store.<이름>으로 등록됩니다.
  • Store는 하위 폴더에서도 재귀적으로 인식합니다. 폴더는 정리 용도이며 파일 이름은 전체 app/stores에서 고유해야 합니다.
  • 상태와 상태를 변경하는 함수를 한 파일에 두며 별도 import, reactive나 상태 관리 패키지가 필요하지 않습니다.
  • store 파일은 영문 변수 형식의 이름을 사용하고 app/stores 바로 아래에 둡니다.
  • 함수는 같은 모듈의 상태를 this로 읽고 변경할 수 있습니다.
  • 각 store 모듈의 타입을 자동 생성하므로 Cake20 View TSX에서 자동완성을 제공합니다.
// app/stores/cart.store.ts
type CartItem = {
  id: string;
  name: string;
  price: number;
  count: number;
};

export const config = {
  // "none": 새로고침까지 | "session": 현재 탭까지 | "local": 브라우저를 닫아도 유지
  persist: "local"
} as const;

export default {
  items: [] as CartItem[],

  add(item: Omit<CartItem, "count">) {
    const found = this.items.find((row) => row.id === item.id);
    if (found) {
      found.count++;
      return;
    }
    this.items.push({ ...item, count: 1 });
  },

  remove(id: string) {
    this.items = this.items.filter((item) => item.id !== id);
  },

  clear() {
    this.items = [];
  }
};

Cake20 View에서 사용

  • store는 모든 Cake20 View 페이지, 레이아웃과 컴포넌트에서 import 없이 사용합니다.
  • 상태는 반응형으로 제공되므로 직접 읽거나 함수로 변경하면 화면이 즉시 갱신됩니다.
  • 브라우저 UI 전용 인터페이스이므로 API, Task, Job 같은 서버 코드에서는 사용하지 않습니다.
export const computed = {
  total: () =>
  store.cart.items.reduce(
    (sum, item) => sum + item.price * item.count,
    0
  )
};

export const addCake = () => {
  store.cart.add({
    id: "strawberry",
    name: "딸기 케이크",
    price: 32000
  });
};

export default () => (
  <>
    <Button onClick={addCake}>장바구니 담기</Button>
    <p>{store.cart.items.length}종 · {computed.total().toLocaleString()}원</p>
  </>
);

저장 방식

  • 현재 store config에서 설정할 수 있는 항목은 persist 하나입니다.
  • none은 메모리, session은 sessionStorage, local은 localStorage에 해당 모듈의 상태를 JSON으로 저장합니다.
  • config 또는 persist를 생략하면 persist: "none"과 같이 현재 페이지 메모리에만 유지합니다.
  • 저장된 값은 시작할 때 default 상태에 병합되므로 파일에 선언한 함수는 유지됩니다.
  • local 모듈은 같은 웹사이트의 다른 탭에서 변경되면 자동으로 동기화됩니다.
  • 테스트 주소와 운영 주소는 origin이 달라 저장 상태도 서로 섞이지 않습니다.
  • 관리자 안의 UI 프리뷰도 웹사이트별 base 경로로 저장 영역을 분리합니다.
  • 함수, 순환 참조와 JSON으로 표현할 수 없는 값은 저장 상태로 사용하지 않습니다.
  • 인증 토큰, 비밀번호, Secret과 민감정보는 store에 저장하지 않습니다. 로그인은 서버 auth의 HttpOnly 쿠키를 사용합니다.
// 브라우저를 닫았다 열어도 유지
export const config = { persist: "local" } as const;

// 현재 탭을 닫을 때까지 유지
export const config = { persist: "session" } as const;

// 메모리에서만 유지하고 새로고침하면 초기화
export const config = { persist: "none" } as const;

// 한 모듈 또는 모든 모듈을 기본값으로 초기화
store.$reset("cart");
store.$reset();