阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 状态管理规范

状态管理规范

作者:陈川 阅读数:11575人阅读 分类: 前端综合

组件开发规范

组件化开发是前端工程化的核心实践之一。良好的组件规范能提升代码复用率、降低维护成本。以下从设计原则、目录结构、props定义等方面展开说明。

组件设计原则

单一职责原则要求每个组件只做一件事。比如按钮组件只处理点击交互,不包含业务逻辑:

// Bad: 按钮混入业务逻辑
function OrderButton() {
  const handleClick = () => {
    fetch('/api/submit-order')
  }
  return <button onClick={handleClick}>提交订单</button>
}

// Good: 纯UI组件
function Button({ onClick, children }) {
  return <button onClick={onClick}>{children}</button>
}

目录结构规范

推荐按功能划分的扁平化结构,避免过深嵌套:

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

Props设计规范

使用TypeScript严格定义props类型,必填项需标记为required:

interface AvatarProps {
  size: 'small' | 'medium' | 'large'
  src: string
  alt: string
  shape?: 'circle' | 'square'  // 可选参数
  className?: string
}

function Avatar({ size, src, alt, shape = 'circle' }: AvatarProps) {
  // 组件实现
}

样式隔离方案

推荐CSS Modules或Styled Components实现样式隔离:

/* 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>
  )
}

状态管理规范

前端应用复杂度提升时,需要系统化的状态管理方案。以下从状态分类、管理策略、性能优化等维度说明。

状态分类标准

按作用域划分状态类型:

  1. 本地状态:组件内部使用,如input值
function Search() {
  const [query, setQuery] = useState('')
  return <input value={query} onChange={e => setQuery(e.target.value)} />
}
  1. 全局状态:跨组件共享,如用户信息
// store/user.ts
export const userStore = atom({
  key: 'user',
  default: null
})

// 组件中使用
function Avatar() {
  const user = useRecoilValue(userStore)
  return <img src={user.avatar} />
}

状态管理选型

根据场景选择合适方案:

方案 适用场景 示例
Context API 低频更新的全局状态 主题/语言切换
Redux 复杂状态逻辑 购物车流程
MobX 响应式编程场景 实时仪表盘
Recoil 细粒度状态订阅 表单联动

状态更新规范

避免直接修改状态,遵循不可变原则:

// 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
  ))
}

性能优化策略

大规模状态需考虑渲染优化:

  1. 使用选择器避免不必要的渲染
const completedTodos = selector({
  key: 'completedTodos',
  get: ({get}) => {
    const todos = get(todoListState)
    return todos.filter(todo => todo.completed)
  }
})
  1. 批量更新状态
// React 18自动批处理
function handleClick() {
  setName('Alice')
  setAge(30) // 只会触发一次渲染
}

代码组织最佳实践

项目规模增长时,需要规范化的代码组织方式。

按功能划分模块

避免按技术类型分目录(如reducers/、components/),推荐按业务功能组织:

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

自定义Hook规范

将复杂逻辑封装为Hook,命名以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 }
}

// 使用示例
function UserList() {
  const { page, nextPage } = usePagination()
  // ...
}

类型定义管理

公共类型应集中定义,组件私有类型可放在组件目录:

// 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
}

异常处理机制

健壮的应用需要统一的错误处理方案。

组件错误边界

使用React Error Boundary捕获组件错误:

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
  }
}

异步操作处理

规范loading/error状态管理:

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 }
}

状态回滚机制

操作失败时应恢复之前状态:

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 Library编写组件测试:

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)
})

状态测试策略

验证状态管理逻辑的正确性:

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测试规范

关键业务流程需添加端到端测试:

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核心知识点

下一篇:事件处理规范

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌