Skip to main content

react-ui-patterns

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

소스 정보

저장소
davila7/claude-code-templates
최근 소스 활동
2026년 1월 25일 15:01
감지된 SKILL.md 언어
영어
스타
33,057
포크
3,842

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
react-ui-patterns
description
Modern React UI patterns for loading states, error handling, and data fetching. Use when building UI components, handling async data, or managing UI states.
# 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.** ```typescript // 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} />; ``` ```typescript // 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 When | Use Spinner When | |-------------------|------------------| | Known content shape | Unknown content shape | | List/card layouts | Modal actions | | Initial page load | Button submissions | | Content placeholders | Inline 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.** ```typescript // 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 ```typescript 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 ```tsx <Button onClick={handleSubmit} isLoading={isSubmitting} disabled={!isValid || isSubmitting} > Submit </Button> ``` ### Disable During Operations **CRITICAL: Always disable triggers during async operations.** ```tsx // 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: ```tsx // WRONG - No empty state return <FlatList data={items} />; // CORRECT - Explicit empty state return ( <FlatList data={items} ListEmptyComponent={<EmptyState />} /> ); ``` ### Contextual Empty States ```tsx // 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 ```tsx 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 ```typescript // WRONG - Spinner when data exists (causes flash) if (loading) return <Spinner />; // CORRECT - Only show loading without data if (loading && !data) return <Spinner />; ``` ### Error Handling ```typescript // 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 ```typescript // 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
GitHub에서 보기