본문으로 건너뛰기
cccskills
무료GitHub에 공개

react-ui-patterns

Build React interfaces that clearly handle loading, errors, empty results, and submissions. Use examples and checklists to keep existing data visible during refetching, offer retry actions, and disable buttons while asynchronous operations are running.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

원문원문 설명 보기

Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states.

설치 방법 보기

이럴 때 유용합니다

  • Keeping existing data visible during refetching
  • Adding visible errors and retry actions
  • Showing guidance when lists or search results are empty
  • Preventing repeated submissions with button states

포함된 파일(1)

  • SKILL.md6.3 KB

SKILL.md(원문)

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

React UI Patterns

Core Principles

  1. Never show stale UI - Loading spinners only when actually loading
  2. Always surface errors - Users must know when something fails
  3. Optimistic updates - Make the UI feel instant
  4. Progressive disclosure - Show content as it becomes available
  5. Graceful degradation - Partial data is better than no data

Loading State Patterns

The Golden Rule

Show loading indicator ONLY when there's no data to display.

// CORRECT - Only show loading when no data exists
const { data, loading, error } = useGetItemsQuery();

if (error) return <ErrorState error={error} onRetry={refetch} />;
if (loading && !data) return <LoadingState />;
if (!data?.items.length) return <EmptyState />;

return <ItemList items={data.items} />;
// WRONG - Shows spinner even when we have cached data
if (loading) return <LoadingState />; // Flashes on refetch!

Loading State Decision Tree

Is there an error?
  → Yes: Show error state with retry option
  → No: Continue

Is it loading AND we have no data?
  → Yes: Show loading indicator (spinner/skeleton)
  → No: Continue

Do we have data?
  → Yes, with items: Show the data
  → Yes, but empty: Show empty state
  → No: Show loading (fallback)

Skeleton vs Spinner

Use Skeleton WhenUse Spinner When
Known content shapeUnknown content shape
List/card layoutsModal actions
Initial page loadButton submissions
Content placeholdersInline operations

Error Handling Patterns

The Error Handling Hierarchy

1. Inline error (field-level) → Form validation errors
2. Toast notification → Recoverable errors, user can retry
3. Error banner → Page-level errors, data still partially usable
4. Full error screen → Unrecoverable, needs user action

Always Show Errors

CRITICAL: Never swallow errors silently.

// CORRECT - Error always surfaced to user
const [createItem, { loading }] = useCreateItemMutation({
  onCompleted: () => {
    toast.success({ title: 'Item created' });
  },
  onError: (error) => {
    console.error('createItem failed:', error);
    toast.error({ title: 'Failed to create item' });
  },
});

// WRONG - Error silently caught, user has no idea
const [createItem] = useCreateItemMutation({
  onError: (error) => {
    console.error(error); // User sees nothing!
  },
});

Error State Component Pattern

interface ErrorStateProps {
  error: Error;
  onRetry?: () => void;
  title?: string;
}

const ErrorState = ({ error, onRetry, title }: ErrorStateProps) => (
  <div className="error-state">
    <Icon name="exclamation-circle" />
    <h3>{title ?? 'Something went wrong'}</h3>
    <p>{error.message}</p>
    {onRetry && (
      <Button onClick={onRetry}>Try Again</Button>
    )}
  </div>
);

Button State Patterns

Button Loading State

<Button
  onClick={handleSubmit}
  isLoading={isSubmitting}
  disabled={!isValid || isSubmitting}
>
  Submit
</Button>

Disable During Operations

CRITICAL: Always disable triggers during async operations.

// CORRECT - Button disabled while loading
<Button
  disabled={isSubmitting}
  isLoading={isSubmitting}
  onClick={handleSubmit}
>
  Submit
</Button>

// WRONG - User can tap multiple times
<Button onClick={handleSubmit}>
  {isSubmitting ? 'Submitting...' : 'Submit'}
</Button>

Empty States

Empty State Requirements

Every list/collection MUST have an empty state:

// WRONG - No empty state
return <FlatList data={items} />;

// CORRECT - Explicit empty state
return (
  <FlatList
    data={items}
    ListEmptyComponent={<EmptyState />}
  />
);

Contextual Empty States

// Search with no results
<EmptyState
  icon="search"
  title="No results found"
  description="Try different search terms"
/>

// List with no items yet
<EmptyState
  icon="plus-circle"
  title="No items yet"
  description="Create your first item"
  action={{ label: 'Create Item', onClick: handleCreate }}
/>

Form Submission Pattern

const MyForm = () => {
  const [submit, { loading }] = useSubmitMutation({
    onCompleted: handleSuccess,
    onError: handleError,
  });

  const handleSubmit = async () => {
    if (!isValid) {
      toast.error({ title: 'Please fix errors' });
      return;
    }
    await submit({ variables: { input: values } });
  };

  return (
    <form>
      <Input
        value={values.name}
        onChange={handleChange('name')}
        error={touched.name ? errors.name : undefined}
      />
      <Button
        type="submit"
        onClick={handleSubmit}
        disabled={!isValid || loading}
        isLoading={loading}
      >
        Submit
      </Button>
    </form>
  );
};

Anti-Patterns

Loading States

// WRONG - Spinner when data exists (causes flash)
if (loading) return <Spinner />;

// CORRECT - Only show loading without data
if (loading && !data) return <Spinner />;

Error Handling

// WRONG - Error swallowed
try {
  await mutation();
} catch (e) {
  console.log(e); // User has no idea!
}

// CORRECT - Error surfaced
onError: (error) => {
  console.error('operation failed:', error);
  toast.error({ title: 'Operation failed' });
}

Button States

// WRONG - Button not disabled during submission
<Button onClick={submit}>Submit</Button>

// CORRECT - Disabled and shows loading
<Button onClick={submit} disabled={loading} isLoading={loading}>
  Submit
</Button>

Checklist

Before completing any UI component:

UI States:

  • Error state handled and shown to user
  • Loading state shown only when no data exists
  • Empty state provided for collections
  • Buttons disabled during async operations
  • Buttons show loading indicator when appropriate

Data & Mutations:

  • Mutations have onError handler
  • All user actions have feedback (toast/visual)

Integration with Other Skills

  • graphql-schema: Use mutation patterns with proper error handling
  • testing-patterns: Test all UI states (loading, error, empty, success)
  • formik-patterns: Apply form submission patterns

리뷰

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

댓글

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

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

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

0 / 1,000자

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

같은 저장소의 스킬

Build screens, forms, and lists with shared UI components and design tokens, named values for spacing, colors, and typography. Provides patterns for consistent layouts, button variants, validation messages, and reusable component properties.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Building screens with shared UI components
  • Replacing fixed colors and spacing with design tokens
  • Creating consistent forms and list layouts
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

Build forms with Formik and yup, a library for defining input validation rules. Apply field errors, submission feedback, edit detection, and step-specific validation to login screens, editing forms, and forms split across multiple steps.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Building login and registration forms
  • Adding conditional input validation
  • Editing existing records with change detection
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

Build GraphQL data queries and updates with separate operation files and generated types and hooks, reusable functions for React. Follow Apollo Client patterns for error messages, loading feedback, cache updates, and reusable field selections.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Building a GraphQL list view
  • Adding data creation or update forms
  • Generating types and hooks from operation files
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

Investigate bugs and failing tests through four stages: finding the root cause, comparing working patterns, testing a hypothesis, and implementing a fix. Uses reproduction steps, diagnostic evidence, and regression tests to check the result.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Tracing the cause of a failing test
  • Following runtime errors back to invalid data
  • Finding the change that broke working code
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

Write Jest unit tests for component behavior and user interactions. Includes reusable test data builders, mock replacements for dependencies, and test-driven development, where a failing test guides implementation before the code is cleaned up.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Testing component rendering and form interactions
  • Creating reusable test data with selective overrides
  • Replacing modules and GraphQL hooks in tests
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

ChrisWiles의 스킬 모두 보기

이 스킬의 문제 신고