redux 文档到底说了什么(上)

本文通过逐步优化实现一个todo app,详细解读redux文档中推荐的代码组织方式和工具,包括使用`combineReducers`、`React + Redux`集成、`selector`、`action creator`、`thunk`中间件、`immer`简化reducer和数据规范化等。通过重构,展示了如何提升代码质量和性能,并引入了`React.memo`和`useCallback`优化React组件。文章最后探讨了redux工具链的简化,如redux-toolkit。
摘要由CSDN通过智能技术生成

前言

最近又认真重读了一遍 redux 的文档,不出意料,还是一样的晦涩难懂。

虽然文档写得不怎么样,但是里面确实给了很多比较好的代码组织方式,推荐了很多很有用的工具和插件,也慢慢地理解为什么这么简单的一个状态中心可以搞出这么多概念和库。

redux 文档除了一些概念的介绍,主要包含了

  1. 怎么只用 redux 这个库来组织 redux 代码
  2. 怎么用 redux-toolkit 的 API 更智能地组织 redux 代码

redux 文档之所以难以看懂是因为它不按线性的思维来写,很多时候突然就冒出一个概念或者方法,而且总是将 reduxreact-reduxredux-toolkit 这三个玩意混在一起讲,搞得看的人是一脸蒙逼。

而这篇文章通过一步步的代码优化来呈现 redux 的最佳写法。(注:这里的最佳写法的范围仅限于 redux 文档,当然还有很多更好的写法这里不讨论)

这里给出文章的最终代码 https://github.com/learn-redux/learn-redux/tree/master/src/apps/ReactReduxTodo

好了,现在开始我们的探索 redux 之旅吧~


需求 - todo app

我们就以做一个 todo list 来作为我们的需求吧,主要涉及到 todo 的增,删,改,查的操作。对于复杂的页面也只是多个资源的增,删,改,查,所以 todo app 是一个非常好的样例。

app 参照如下

第一版 - 乞丐版的 todo app

乞丐版的意思是,我们只使用 redux 去本地测试里跑 todo app。先搞 reducer.tsstore.ts

// reducer.ts
const initTodos: TTodo[] = [
  {
   
    id: '1',
    text: '抽烟',
    state: 'done'
  },
  {
   
    id: '2',
    text: '喝酒',
    state: 'todo'
  },
  {
   
    id: '3',
    text: '烫头',
    state: 'todo'
  }
]

const initFilter: TFilter = 'all'

const initState = {
   
  todos: initTodos,
  filter: initFilter
}

const reducer = (state = initState , action: any) => {
   
  switch (action.type) {
   
    case 'addTodo':
      const newTodos = [...state.todos, action.payload]
      
      return {
   ...state, todos: newTodos}
    case 'removeTodo':
      const newTodos = state.todos.filter(todo => todo.id !== action.payload)
      
      return {
    ...state, todos : newTodos }
    case 'toggleTodo':
      const newTodos = state.todos.map(todo =>
        todo.id === action.payload
          ? {
   ...todo, state: todo.state === 'todo' ? 'done' : 'todo'}
          : todo
      )
      
      return {
    ...state, todos: newTodos }
    case 'setFilter':
      return {
    ...state filter: action.payload }
    case 'reset':
      return initState
    default:
      return state
  }
}

export default reducer
// store.ts
import {
   createStore} from "redux"
import reducer from "./reducer"

const store = createStore(reducer)

store.subscribe(() => console.log('update component'))

export default store

测试代码,因为篇幅问题,这里只展示一个用例。

// app.test.ts
it('可以添加一条 Todo', () => {
   
  const newTodo: TTodo = {
   
    id: '99',
    text: '吃好吃的',
    state: 'todo',
  }

  store.dispatch({
   type: 'addTodo', payload: newTodo})

  const todos = store.getState().todos
  expect(todos[todos.length - 1]).toEqual(newTodo)
})

这里测试会正常显示最后一个 todo 就是“吃好吃的”。

这里的 store 主要是 todo 列表和过滤器 filter,代码也很简单,无非就是添加 todo、删除 todo、toggle todo,reset 一些基本操作。

第二版:用 combineReducers 来做 slice

这里注意到在这个 redcuer 里其实包含了对 todos 和 filter 的操作,整个 reducer 看起来很冗长,因此我们会想将 todos 就搞 todosReducer 来管, filter 就用 filterReducer 来管,这种分开管理的子 store 被称为 “slice”

上面的 reducer 代码可以改写成:

const todosReducer = (todos: TTodo[] = initTodos, action: any) => {
   
  switch (action.type) {
   
    case 'addTodo':
      return [...todos, action.payload]
    case 'removeTodo':
      return todos.
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写代码的海怪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值