阿里云主机折上折
  • 微信号
Current Site:Index > State management specification

State management specification

Author:Chuan Chen 阅读数:11576人阅读 分类: 前端综合

Component Development Standards

Component-based development is a core practice of front-end engineering. Good component standards can improve code reusability and reduce maintenance costs. The following elaborates on design principles, directory structure, props definition, and more.

Component Design Principles

The Single Responsibility Principle requires each component to do only one thing. For example, a button component should only handle click interactions without containing business logic:

// Bad: Button mixed with business logic
function OrderButton() {
  const handleClick = () => {
    fetch('/api/submit-order')
  }
  return <button onClick={handleClick}>Submit Order</button>
}

// Good: Pure UI component
function Button({ onClick, children }) {
  return <button onClick={onClick}>{children}</button>
}

Directory Structure Standards

A flat structure organized by functionality is recommended, avoiding excessive nesting:

components/
├── Form/
│   ├── Input/
│   │   ├── index.tsx
│   │   ├── style.module.css
│   │   └── types.ts
│   └── Select/
├── Feedback/
│   ├── Toast/
│   └── Modal/
└── Navigation/
    ├── Tabs/
    └── Breadcrumb/

Props Design Standards

Use TypeScript to strictly define props types, with required fields marked as required:

interface AvatarProps {
  size: 'small' | 'medium' | 'large'
  src: string
  alt: string
  shape?: 'circle' | 'square'  // Optional parameter
  className?: string
}

function Avatar({ size, src, alt, shape = 'circle' }: AvatarProps) {
  // Component implementation
}

Style Isolation Solutions

CSS Modules or Styled Components are recommended for style isolation:

/* Button.module.css */
.primary {
  background: #1890ff;
  &:hover {
    background: #40a9ff;
  }
}
import styles from './Button.module.css'

function Button({ type }) {
  return (
    <button className={styles[type]}>
      {children}
    </button>
  )
}

State Management Standards

As front-end applications grow in complexity, systematic state management solutions are needed. The following explains state classification, management strategies, and performance optimization.

State Classification Criteria

Classify state types by scope:

  1. Local State: Used within a component, such as input value
function Search() {
  const [query, setQuery] = useState('')
  return <input value={query} onChange={e => setQuery(e.target.value)} />
}
  1. Global State: Shared across components, such as user information
// store/user.ts
export const userStore = atom({
  key: 'user',
  default: null
})

// Usage in components
function Avatar() {
  const user = useRecoilValue(userStore)
  return <img src={user.avatar} />
}

State Management Selection

Choose the appropriate solution based on the scenario:

Solution Suitable Scenarios Example
Context API Global state with low update frequency Theme/language switching
Redux Complex state logic Shopping cart flow
MobX Reactive programming scenarios Real-time dashboard
Recoil Fine-grained state subscriptions Form linkage

State Update Standards

Avoid directly modifying state; follow the immutability principle:

// Bad
const [todos, setTodos] = useState([])
const handleComplete = (id) => {
  todos.find(todo => todo.id === id).completed = true
  setTodos(todos)
}

// Good
const handleComplete = (id) => {
  setTodos(prev => prev.map(todo => 
    todo.id === id ? { ...todo, completed: true } : todo
  ))
}

Performance Optimization Strategies

For large-scale state, consider rendering optimizations:

  1. Use selectors to avoid unnecessary renders
const completedTodos = selector({
  key: 'completedTodos',
  get: ({get}) => {
    const todos = get(todoListState)
    return todos.filter(todo => todo.completed)
  }
})
  1. Batch state updates
// React 18 automatic batching
function handleClick() {
  setName('Alice')
  setAge(30) // Only triggers one render
}

Code Organization Best Practices

As project size grows, standardized code organization is needed.

Organize by Feature

Avoid organizing by technical type (e.g., reducers/, components/); instead, organize by business functionality:

features/
├── auth/
│   ├── components/
│   ├── hooks/
│   └── store/
├── product/
│   ├── api/
│   ├── types/
│   └── utils/
└── order/
    ├── constants/
    └── helpers/

Custom Hook Standards

Encapsulate complex logic into Hooks, prefixed with use:

function usePagination(initialPage = 1) {
  const [page, setPage] = useState(initialPage)
  
  const nextPage = () => setPage(p => p + 1)
  const prevPage = () => setPage(p => Math.max(1, p - 1))

  return { page, nextPage, prevPage }
}

// Usage example
function UserList() {
  const { page, nextPage } = usePagination()
  // ...
}

Type Definition Management

Public types should be centrally defined, while component-private types can reside in the component directory:

// types/app.ts
export interface User {
  id: string
  name: string
  roles: Array<'admin' | 'editor'>
}

// components/UserCard/types.ts
export interface UserCardProps {
  user: User
  showContact?: boolean
}

Exception Handling Mechanisms

Robust applications require unified error handling solutions.

Component Error Boundaries

Use React Error Boundary to catch component errors:

class ErrorBoundary extends React.Component {
  state = { hasError: false }

  static getDerivedStateFromError() {
    return { hasError: true }
  }

  componentDidCatch(error, info) {
    logErrorToService(error, info)
  }

  render() {
    if (this.state.hasError) {
      return <FallbackUI />
    }
    return this.props.children
  }
}

Asynchronous Operation Handling

Standardize loading/error state management:

function useAsync(asyncFn) {
  const [state, setState] = useState({
    loading: false,
    error: null,
    data: null
  })

  const execute = useCallback(() => {
    setState({ loading: true, error: null, data: null })
    return asyncFn()
      .then(data => setState({ loading: false, error: null, data }))
      .catch(error => setState({ loading: false, error, data: null }))
  }, [asyncFn])

  return { ...state, execute }
}

State Rollback Mechanism

Revert to the previous state on operation failure:

function useUndoState(initialValue) {
  const [states, setStates] = useState([initialValue])
  const [index, setIndex] = useState(0)

  const current = states[index]
  const setCurrent = (newValue) => {
    setStates(prev => [...prev.slice(0, index + 1), newValue])
    setIndex(prev => prev + 1)
  }

  const undo = () => index > 0 && setIndex(prev => prev - 1)
  const redo = () => index < states.length - 1 && setIndex(prev => prev + 1)

  return [current, setCurrent, { undo, redo }]
}

Testing Standards

Comprehensive testing is a critical part of quality assurance.

Component Testing Points

Use Testing Library to write component tests:

import { render, screen, fireEvent } from '@testing-library/react'

test('Button click triggers callback', () => {
  const handleClick = jest.fn()
  render(<Button onClick={handleClick}>OK</Button>)
  
  fireEvent.click(screen.getByText('OK'))
  expect(handleClick).toHaveBeenCalledTimes(1)
})

State Testing Strategy

Verify the correctness of state management logic:

test('todo reducer adds new item', () => {
  const initialState = { todos: [] }
  const action = { type: 'ADD_TODO', payload: 'Learn React' }
  
  const newState = todoReducer(initialState, action)
  expect(newState.todos).toHaveLength(1)
  expect(newState.todos[0].text).toBe('Learn React')
})

E2E Testing Standards

Add end-to-end tests for critical business workflows:

describe('Checkout Flow', () => {
  it('should complete purchase', () => {
    cy.visit('/products')
    cy.get('[data-testid="product-1"]').click()
    cy.contains('Add to Cart').click()
    cy.visit('/cart')
    cy.contains('Checkout').click()
    cy.url().should('include', '/checkout/success')
  })
})

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:Git核心知识点

下一篇:事件处理规范

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.