본문으로 건너뛰기
cccskills
무료GitHub에 공개한국어 소개

data-fetching-architecture

SWR을 활용한 클라이언트 데이터 요청 구조를 안내합니다. API 호출을 서비스와 스토어 훅에 배치하고 로딩 및 오류 상태, 쓰기 후 캐시 갱신을 다루며 컴포넌트의 `useEffect` 요청을 옮기는 방법을 설명합니다.

원문원문 설명 보기

Use for client APIs, SWR hooks, cache invalidation, async errors, useEffect migration, home first paint and persistent caches.

lobehub/lobehub스타 83,509(GitHub 83,509 + cccskills 0)

실행 점수 미검증

설치 방법 보기

이럴 때 유용합니다

  • 컴포넌트 요청을 스토어 훅으로 옮기기
  • 업데이트 후 오래된 캐시 수정
  • 로딩·빈 결과·오류 표시 정리

한국어 소개

할 수 있는 일

서비스, 스토어 훅, 컴포넌트로 클라이언트 데이터 요청을 나누는 방법을 안내합니다. 읽기에는 useClientDataSWR를 사용하고 API 호출은 서비스에 둡니다. 캐시 키 공유, 쓰기 후 데이터 갱신, 대기 상태 관리, 최초 로딩과 빈 결과 및 오류 구분을 다룹니다. useEffect 안의 요청과 컴포넌트 상태에 중복 저장된 데이터를 스토어 훅과 선택자로 옮기는 작업에도 활용할 수 있습니다. 로컬 복사본으로 렌더링하는 목록과 상세 화면에는 Replica 동기화 방법을 안내합니다.

이럴 때 유용합니다

화면에 오래된 데이터가 남거나 요청이 계속 로딩 중으로 보이는 문제, 최초 요청 오류가 빈 결과처럼 표시되는 문제를 살펴볼 때 유용합니다. 데이터 요청을 어디에 둘지 정리할 때도 사용할 수 있습니다.

사용 예시

  • “이 컴포넌트의 요청을 스토어의 SWR 훅으로 옮겨 주세요.”
  • “업데이트 후 목록이 오래된 상태로 남는 원인을 찾아 주세요.”
  • “최초 요청 오류와 빈 결과를 구분하는 방법을 알려 주세요.”

주의 사항

LobeHub의 기존 래퍼와 코드 구조에 맞춰 구현합니다. SWR의 기본 동작을 그대로 가정하지 말고 실제 래퍼 설정을 확인해야 합니다.

이 소개문은 공개된 SKILL.md를 바탕으로 AI(OpenAI Codex)가 작성했습니다. 정확한 사양은 아래 원문을 확인하세요.

문서 점검

AI가 SKILL.md의 내용에서 주의가 필요한 작업과 도입 전제를 확인했습니다. 점수는 실제로 실행한 결과(실행 검증)만으로 매깁니다.

안전성전송·삭제·명령 실행 등을 명시하고 있는가
A양호낙관적 쓰기 실패 시 롤백과 삭제 처리를 명시합니다.
도입의 용이성필요한 도구나 API 키가 적고 적혀 있는가
B일부 부족SWR과 LobeHub 래퍼를 전제로 하지만 설치 절차는 없습니다.

점수에는 넣지 않았습니다. 2026년 10월 26일 기준으로 AI(OpenAI Codex)가 판정했습니다. 참고용이므로 설치 전에 원문도 확인해 주세요.

평가가 다르다고 생각되면 재검토를 요청하기

어느 항목이 왜 다르다고 생각하는지 적어 주세요. 로그인은 필요 없습니다. SKILL.md와 대조해 평가를 다시 만들고 이곳에 반영합니다.

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

포함된 파일(3)

  • SKILL.md7.0 KB
  • references/home-first-paint.md3.9 KB
  • references/walkthrough.md3.5 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

LobeHub Data Fetching Architecture

Component → Store useFetchXxx hook → Service → lambdaClient
          ← SWR request state + store data ← response

Layer boundaries

  • Services in src/services/ own API calls: .query() for reads, .mutate() for writes. Export a service instance per domain; components and stores do not call lambdaClient directly.
  • Store read hooks use useClientDataSWR and return its SWR response, including error and mutate. Sync successful results into the store through the wrapper's supported callback (onSuccess, or onData for the sync wrapper).
  • Server lists and details that paint from a local copy go through @/libs/replica instead: the store's useFetchXxx returns slice.useSync(params) (flags only) and the engine writes the store. See the Replica section of zustand.
  • Components call these hooks and read store data through selectors. Do not fetch in useEffect or duplicate server data in component useState.
  • Use useFetchXxx for read hooks and refreshXxx for cache invalidation.
  • For list/detail types, maps, reducers, and shared type sources, use Zustand data structures. For store layout and action classes, use zustand.

Home First Paint and Persistent Caches

When changing home/sidebar first paint or persisted display data, read references/home-first-paint.md. It covers avoiding flicker, reusing persistence, and the user displaySnapshot.ts boundary.

Cache keys and refresh

Reuse the domain key factory in src/libs/swr/keys.ts; define a shared key if the domain has none. Include every parameter that changes the response: entity or parent id, filters, sort, and pagination. Read and refresh must construct the same key.

Import useClientDataSWR and mutate from @/libs/swr, keeping the application's workspace/cache handling. Return a null key when a required id is absent; passing undefined to a store hook only disables fetching if that hook maps it to null.

For example, inside an action class:

useFetchBenchmarks = () =>
  useClientDataSWR(evalKeys.benchmarks(), () => agentEvalService.listBenchmarks(), {
    onSuccess: (data) => {
      this.#set({ benchmarkList: data, benchmarkListInit: true });
    },
  });

refreshBenchmarks = async () => {
  await mutate(evalKeys.benchmarks());
};

Read the current benchmark action for store wiring and the SWR wrappers for their actual options. These links locate implementation; they do not make every existing call site a template to copy unchanged.

Hooks that share a known parent id can run together. If one request needs a value returned by another, keep its key null until that value exists. Do not assume the application wrapper uses upstream SWR's default deduplication interval.

For lists cached separately under multiple parents, see parent-keyed lists. Ordinary flat lists need no extra layer.

Mutations

  • Call the service, then refresh affected list/detail keys and any related domain whose response changed. Await refresh when subsequent UI behavior depends on it.
  • Keep pending flags in store state and clear them in finally. Use per-id state for row updates/deletes so unrelated rows remain usable; create can use a separate flag because no persistent id exists yet.
  • For optimistic writes on replica data, use slice.optimistic / entity.optimistic; a rejected call rolls back on its own, deletes included.
  • For optimistic create/update on legacy stores, use the store's reducer/dispatch convention and restore or revalidate affected state if the service fails. Do not leave a temporary row or a successful-looking edit after rejection. Delete only after server success there: a hand-written reducer has no rollback base.
  • Let failures reach the caller's error UI; a finally block clears pending state but does not by itself recover an optimistic write.

Render loading, errors, and settled data

Consume the read hook's SWR response. Success-only flags such as isInit, missing map entries, and data ?? [] cannot distinguish an initial request failure from loading or empty results.

Use AsyncBoundary for standard loading/error/empty/data surfaces; use AsyncError for custom layouts and inline failures. Pass the original SWR data to the boundary: undefined means no successful result, whereas [] is a settled empty result.

Replica useSync returns no data. Feed AsyncBoundary its error and a settled signal from the store entry (data={isListInit || undefined}, where the selector is entry !== undefined); see src/features/Pages/PageLayout/Body/index.tsx.

const BenchmarkList = () => {
  const useFetchBenchmarks = useEvalStore((s) => s.useFetchBenchmarks);
  const benchmarks = useEvalStore((s) => s.benchmarkList);
  const { data, error, isLoading, mutate } = useFetchBenchmarks();

  return (
    <AsyncBoundary
      data={data}
      empty={<EmptyState />}
      error={error}
      isEmpty={data?.length === 0}
      isLoading={isLoading}
      onRetry={() => {
        void mutate();
      }}
    >
      <BenchmarkCards items={benchmarks} />
    </AsyncBoundary>
  );
};

The example's EmptyState and BenchmarkCards stand for the surface's existing renderers. Follow these distinctions when adapting it:

  • Show first-load errors before empty / NotFound / zero-value defaults. Do not put an error branch after if (!map[id]) return <Skeleton />; failure may never fill the map.
  • Preserve settled content during background revalidation failures, including a successfully loaded empty list. A retry in flight should show pending feedback.
  • In a fetched + static list, use the fetched slice's request state before combining rows. Static rows must not hide a failed request.
  • For infinite scroll, keep a per-bucket loadMoreError and show an inline Retry row. Suspend observer-triggered retries while that error is unresolved.
  • A closed modal or absent id disables a request; it is not evidence of a missing record.

Migrating an existing fetch

Move the API call into its service and the request into a store SWR hook. Reuse the existing state shape and action organization unless they need to change for the task. Replace the component's effect/local fetch state with that hook and selectors, then connect error, retry, and pending feedback. Refresh the same cache key after writes.

Check initial failure, retry, settled-empty results, background failure, and switching ids against the surface being changed. For stale data, compare read/refresh keys and the store bucket they update; for stuck loading, inspect rejected requests as well as success callbacks. Do not add a second fetch or another loading flag to mask the cause.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

acceptance

무료요약 있음

실제 제품을 적절한 조작 환경에서 실행해 변경 사항을 검증하고, 사용자가 확인할 수 있는 증거를 모아 인수 보고서로 게시합니다. 기존 검증 계획을 확인하거나 점검 항목을 만들고, `lh` CLI로 결과를 게시할 수 있습니다.

  • 변경된 제품 동작을 실제로 확인하기
  • 스크린샷 등 검증 증거 수집하기
  • 검증 계획과 보고서 작성하기
lobehub/lobehub8.4만2026년 10월 26일 업데이트

add-model-provider

무료요약 있음

LobeHub에 AI 모델 제공자를 추가하는 과정을 안내합니다. 런타임 연동, 모델 정보와 설정, 브랜드 표시, 문서화 및 인수 확인을 다루며, 기존 제공자에 모델만 추가하는 경우와 새 연동이 필요한 경우를 구분합니다.

  • LobeHub에 새 AI 모델 제공자 추가하기
  • 제공자의 설정 안내나 설명 갱신하기
  • 모델 추가에 새 제공자 연동이 필요한지 판단하기
lobehub/lobehub8.4만2026년 10월 26일 업데이트

add-setting-env

무료요약 있음

서버 환경 변수로 사용자 설정의 기본값을 지정하도록 구현하는 절차를 안내합니다. 변수 검증, 서버 설정 구성, 사용자 저장소 반영부터 예시 환경 파일과 셀프 호스팅 문서 갱신까지 다룹니다.

  • 환경 변수로 사용자 설정 기본값 지정
  • 설정을 서버 구성과 사용자 저장소에 연결
  • 환경 변수 예시와 문서 갱신
lobehub/lobehub8.4만2026년 10월 26일 업데이트

agent-runtime-hooks

무료요약 있음

에이전트 실행 단계, 도구 호출, 사람의 승인, 컨텍스트 압축, 하위 에이전트 호출에 훅을 등록하는 방법을 안내합니다. 이벤트를 관찰하고 로컬 도구 결과를 모의하거나 설정에 따라 웹훅으로 도구 호출을 허용 또는 거부할 수 있습니다.

  • 에이전트 단계와 오류 기록
  • 테스트 중 도구 결과 모의
  • 웹훅으로 도구 호출 허용 또는 거부
lobehub/lobehub8.4만2026년 10월 26일 업데이트

agent-signal

무료요약 있음

에이전트의 이벤트 기반 백그라운드 작업을 설계하고 구현하도록 돕습니다. 소스, 시그널, 액션, 정책의 역할을 나누고 비동기 처리, 중복 실행 방지, 완료 기록과 관측 기능을 다룹니다.

  • 이벤트로 시작되는 백그라운드 작업 추가
  • 대화 요청과 작업을 분리
  • 액션의 중복 실행 방지
lobehub/lobehub8.4만2026년 10월 26일 업데이트

agent-testing-bot

무료요약 있음

실제 데스크톱 채팅 앱에서 봇 채널의 인수 테스트를 진행합니다. Discord, Slack, Telegram, WeChat, Lark, QQ에서 메시지를 보내고 응답을 기다린 뒤 결과 화면을 캡처합니다. iMessage는 BlueBubbles 브리지를 사용합니다.

  • 실제 Discord 채널에서 봇 응답 확인하기
  • Slack이나 Telegram 대화 경로 테스트하기
  • macOS 앱의 작업 결과 화면으로 기록하기
lobehub/lobehub8.4만2026년 10월 26일 업데이트

lobehub의 스킬 모두 보기

이 스킬의 문제 신고