安装
npx skills add https://github.com/sickn33/antigravity-awesome-skills --skill react-ui-patterns
- React UI Patterns
- Core Principles
- Never show stale UI
- - Loading spinners only when actually loading
- Always surface errors
- - Users must know when something fails
- Optimistic updates
- - Make the UI feel instant
- Progressive disclosure
- - Show content as it becomes available
- 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 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.
- // 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
When to Use
This skill is applicable to execute the workflow or actions described in the overview.
← 返回排行榜