夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 核心概念

  • 高级指引

  • Hook

  • 案例演示

  • Router

  • Redux

    • 入门Redux
    • Redux基础
    • 数据范式化和性能优化
    • Redux Toolkit详细示例
      • Redux Toolkit详细示例
        • 关于 Redux Toolkit
        • 具体示例
  • Jotai

  • Mobx

  • 其他

  • 《React》笔记
  • Redux
夜猫子
2022-11-29
目录

Redux Toolkit详细示例

# Redux Toolkit详细示例

# 关于 Redux Toolkit

官方推荐的标准的 Redux 逻辑开发模式

Redux Toolkit 包含:

  • configureStore() (opens new window):创建一个顶层仓库,其封装了createStore,简化配置项。

    import { configureStore } from '@reduxjs/toolkit'
    import usersReducer from '../features/users/usersSlice'
    import postsReducer from '../features/posts/postsSlice'
    
    export default configureStore({
      reducer: {
        users: usersReducer,
        posts: postsReducer,
      }
    })
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  • createReducer() (opens new window) 将 action type 映射到 reducer 函数,而不是编写 switch...case 语句。另外,它带有 proxy 更新,例如 state.todos[3].completed = true,并且它会自动调用。

  • createAction() (opens new window) 生成给定 action type 字符串的 action creator 函数。该函数本身已定义了 toString(),因此可以代替常量类型使用。

    import { createAction } from '@reduxjs/toolkit'
    const increment = createAction('counter/increment')
    let action = increment()
    // { type: 'counter/increment' }
    action = increment(3)
    // returns { type: 'counter/increment', payload: 3 }
    
    1
    2
    3
    4
    5
    6
  • createSlice() (opens new window) 创建初始化状态 initial state,并自动生成 reducer。

  • createAsyncThunk (opens new window): 接收一个 action type 字符串和一个返回值为 promise 的函数, 并生成一个 thunk 函数,这个 thunk 函数可以基于之前那个 promise ,dispatch 一组 type 为 pending/fulfilled/rejected 的 action。

  • createEntityAdapter (opens new window): 生成一系列可复用的 reducer 和 selector,从而管理 store 中的规范化数据。

  • createSelector (opens new window) 来源于 Reselect (opens new window) 库,(记忆化数据) 并重新 export 出来以方便使用。

# 具体示例

src/features/todos/todosSlice.js

import {
  createSlice,
  createSelector,
  createAsyncThunk,
  createEntityAdapter
} from '@reduxjs/toolkit'
import { client } from '../../api/client'
import { StatusFilters } from '../filters/filtersSlice'

const todosAdapter = createEntityAdapter()

const initialState = todosAdapter.getInitialState({
  status: 'idle'
})

// Thunk 函数
export const fetchTodos = createAsyncThunk('todos/fetchTodos', async () => {
  const response = await client.get('/fakeApi/todos')
  return response.todos
})

export const saveNewTodo = createAsyncThunk('todos/saveNewTodo', async text => {
  const initialTodo = { text }
  const response = await client.post('/fakeApi/todos', { todo: initialTodo })
  return response.todo
})

const todosSlice = createSlice({
  name: 'todos',
  initialState,
  reducers: {
    todoToggled(state, action) {
      const todoId = action.payload
      const todo = state.entities[todoId]
      todo.completed = !todo.completed
    },
    todoColorSelected: {
      reducer(state, action) {
        const { color, todoId } = action.payload
        state.entities[todoId].color = color
      },
      prepare(todoId, color) {
        return {
          payload: { todoId, color }
        }
      }
    },
    todoDeleted: todosAdapter.removeOne,
    allTodosCompleted(state, action) {
      Object.values(state.entities).forEach(todo => {
        todo.completed = true
      })
    },
    completedTodosCleared(state, action) {
      const completedIds = Object.values(state.entities)
        .filter(todo => todo.completed)
        .map(todo => todo.id)
      todosAdapter.removeMany(state, completedIds)
    }
  },
  extraReducers: builder => {
    builder
      .addCase(fetchTodos.pending, (state, action) => {
        state.status = 'loading'
      })
      .addCase(fetchTodos.fulfilled, (state, action) => {
        todosAdapter.setAll(state, action.payload)
        state.status = 'idle'
      })
      .addCase(saveNewTodo.fulfilled, todosAdapter.addOne)
  }
})

export const {
  allTodosCompleted,
  completedTodosCleared,
  todoAdded,
  todoColorSelected,
  todoDeleted,
  todoToggled
} = todosSlice.actions

export default todosSlice.reducer

export const { selectAll: selectTodos, selectById: selectTodoById } =
  todosAdapter.getSelectors(state => state.todos)

export const selectTodoIds = createSelector(
  // 首先,传递一个或多个 input selector 函数:
  selectTodos,
  // 然后,一个 output selector 接收所有输入结果作为参数
  // 并返回最终结果
  todos => todos.map(todo => todo.id)
)

export const selectFilteredTodos = createSelector(
  // 第一个 input selector:所有 todos
  selectTodos,
  // 第二个 input selector:所有 filter 值
  state => state.filters,
  // Output selector: 接收两个值
  (todos, filters) => {
    const { status, colors } = filters
    const showAllCompletions = status === StatusFilters.All
    if (showAllCompletions && colors.length === 0) {
      return todos
    }

    const completedStatus = status === StatusFilters.Completed
    // 根据 filter 条件返回未完成或已完成的 todos
    return todos.filter(todo => {
      const statusMatches =
        showAllCompletions || todo.completed === completedStatus
      const colorMatches = colors.length === 0 || colors.includes(todo.color)
      return statusMatches && colorMatches
    })
  }
)

export const selectFilteredTodoIds = createSelector(
  // 传入记忆化 selector
  selectFilteredTodos,
  // 并在 output selector 中导出数据
  filteredTodos => filteredTodos.map(todo => todo.id)
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

总结

  • Redux Toolkit (RTK) 是编写 Redux 逻辑的标准方式
    • RTK 包含用于简化大多数 Redux 代码的 API
    • RTK 围绕 Redux 核心,并包含其他有用的包
  • configureStore 用来设置一个具有良好默认值的 Redux store
    • 自动组合 slice reducers 来创建根 reducer
    • 自动设置 Redux DevTools 扩展和调试 middleware
  • createSlice 简化了 Redux actions 和 reducers 的编写
    • 根据 slice/reducer 名称自动生成 action creators
    • Reducers 可以使用 Immer 在 createSlice 中“改变”(mutate)state
  • createAsyncThunk 为异步调用生成 thunk
    • 自动生成一个 thunk + pending/fulfilled/rejected action creators
    • dispatch thunk 运行 payload creator 并 dispatch actions
    • 可以在 createSlice.extraReducers 中处理 thunk actions
  • createEntityAdapter 为标准化 state 提供了 reducers + selectors
    • 包括用于常见任务的 reducer 功能,例如添加/更新/删除 items
    • 为 selectAll 和 selectById 生成记忆化 selectors
编辑 (opens new window)
上次更新: 2023/7/11 18:57:41
数据范式化和性能优化
Jotai

← 数据范式化和性能优化 Jotai→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式