10 个步骤轻松掌握 ReduxToolkit

简介: 10 个步骤轻松掌握 ReduxToolkit

如果你在用 React,那你也应该使用 Redux。

如果你在用 Redux,那你也应该使用 RTK。

RTK 全拼 Redux-Toolkit,是 Redux 的官方工具包,致力于让 Redux 更易于使用。

这篇文章将分成 10 个步骤教你快速掌握 RTK。

在阅读之前,你最好知道一些 Redux 的知识。


1. 创建 store


使用 configureStore创建 store。

store 中保存所有的数据以及更新数据的操作(reducer)。

使用 Provide组件包裹你的所有组件。


import { configureStore } from "@reduxjs/toolkit"
import { Provider } from "react-redux"
// 也可以配置 middleware 和 enhancer
const store = configureStore({
  reducer: {
  // 改变数据的函数
  }
})
const Container = () => (
  // Provider 组件可以将 store 以上下文的方式注入到根组件中,这样所有的组件都可以使用上下文
  <Provider store={store}>
    <App />
  </Provider>
)


2. 创建命名切片(slice)


slice 包含一部分状态和可以更新这部分状态的函数。

我们通常以模块来划分 Slice,比如商城系统可以设计成 GoodcartSlice、ShopSlice、OrderSlice 等。

这样做的好处是将业务高内聚,不再为了修改一个 action 而去修改 N 个文件。


import { createSlice } from "@reduxjs/toolkit"
export const counterSlice = createSlice({
  name: 'counter',// 每个 slice 必须有一个名字,而且需要是唯一的。
  // 设置初始状态
  initialState: {
    count: 0
  },
  // reducers 可以自动创建 actions
  reducers: {
  }
})


3. 将 slice 中的 reducer 添加到 store 中


我们在 createSlice 中定义的 reducers(复数)会在 counterSlice 对象上自动创建 reducer(单数)属性。

将 slice.reducer 添加到 store 中。


const store = configureStore({
   reducer: {
     // reducer 的 key 需要和 slice 的 name 保持一致
     counter: counterSlice.reducer// reducer 会根据配置对象的 reducers 自动创建
   }
 })


4. 在 slice 的 reducers 中编写逻辑


reducer 可以获取当前的状态和正在执行的 action,并更新 Slice 中的 state。

RTK 内部自动使用 immer,所以这些 state 的变化都是不可变的。


import { createSlice } from "@reduxjs/toolkit"
export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0
  },
  reducers: {
    // reducers 的每个方法都可以接收到当前的状态
    // 方法的第二个参数可以自动接收 actions,这个例子中没有用到
    up: state => {
      state.count += 1// 这种写法像是在直接改变原数据,但 RTK 会使用 immer 让它变成不可变的操作
    },
    down: state => {
      state.count -= 1
    }
  }
})


5. 使用 useSelector 从 store 中取值


useSelector 函数可以访问 store 中所有的数据,并且可以值返回当前组件所需要的数据。

它是一个 hook,我们可以在任意一个被 Provider 包裹的组件中调用它。


import { useSelector } from "react-redux"
cosnt App = () => {
  // state 参数是 store 的所有数据
  // state.counter 是我们的命名 slice
  // 最后在 slice 中获取需要的值
  const count = useSelector(state => state.counter.count)
  return (
    <div>
      Count: {count}
    </div>)
}


6. 更改 store 的数据时,从 slice 中导出 actions


slice 会根据 reducers 自动生成一个 actions 属性,它包含了一组方法,但是我们不能直接调用,为它们需要当前的 state 和参数。


cosnt App = () => {
  const actions = counterSlice.actions
  // 此时 actions 身上包含两个方法:actions.up 和 actions.down
}


7. 使用 dispatch 调用 actions


我们需要使用 useDispatch hook 来访问 dispatch 函数,然后使用这个函数来调用 actions。

actions 更新 state 后,所有使用 useSelector 访问数据的组件都会自动更新。


cosnt App = () => {
  const count = useSelector(state => state.counter.count)
  const actions = counterSlice.actions
  // dispatch 是个方法,它可以调用 action
  const dispatch = useDispatch()
  // actions.up 会创建一个 action 对象
  const constUp = () => dispatch(actions.up())
  const constDown = () => dispatch(actions.down())
  return (
    <div>
      Count: {count}
      <button onClick={countUp}>+</button>
      <button onClick={countDown}>-</button>
    </div>)
}


8. 为 action 添加参数


action 也可以附带参数,作为 reducer 的第二个参数传入。

传递的数据 RTK 会自动帮我们挂载到 action 的 payload 属性上。


import { createSlice } from "@reduxjs/toolkit"
export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0
  },
  reducers: {
    up: (state, action) => {
      state.count += action.payload || 1
    },
    down: (state, action) => {
      state.count -= action.payload || 1
    }
  }
})

在组件中传递参数。


cosnt App = () => {
  const count = useSelector(state => state.counter.count)
  const actions = counterSlice.actions
  const dispatch = useDispatch()
  const constUp = () => dispatch(actions.up())
  const constDown = () => dispatch(actions.down())
  const plusFive = () => dispatch(actions.up(5))
  const minusFive = () => dispatch(actions.down(5))
  return (
    <div>
      Count: {count}
      <button onClick={countUp}>+</button>
      <button onClick={plusFive}>+ 5</button>
      <button onClick={countDown}>-</button>
      <button onClick={minusFive}>- 5</button>
    </div>)
}


9. 使用 redux-thunk 处理异步操作


因为异步操作非常常见,所以 RTK 内置了 redux-thunk。

处理异步的方式就是创建一个 thunk 函数,它返回一个异步函数,然后在 thunk 函数中使用 dispatch 调用 action。


//  返回的异步函数默认接受 dispatch 作为参数
const fetchLength = () => async dispatch => {
  // 模拟 ajax 获取数据
  const result = await fetch("http://localhost:3000/api/length")
  const text = await result.text()
  const actions = counterSlice.actions
  // 当数据准备完毕后,使用 dispatch 调用 action
  dispatch(actions.up(text.length))
}

在组件中进行异步操作。


cosnt App = () => {
  const count = useSelector(state => state.counter.count)
  const actions = counterSlice.actions
  const dispatch = useDispatch()
  const constUp = () => dispatch(actions.up())
  const constDown = () => dispatch(actions.down())
  const plusFive = () => dispatch(actions.up(5))
  const minusFive = () => dispatch(actions.down(5))
  // 将 thunk 函数像 action 一样传递给 dispatch
  const countAsync = () => dispatch(fetchLength())
  return (
    <div>
      Count: {count}
      <button onClick={countUp}>+</button>
      <button onClick={plusFive}>+ 5</button>
      <button onClick={countDown}>-</button>
      <button onClick={minusFive}>- 5</button>
      <button onClick={countAsync}> async fetch </button>
    </div>)
}


10. Context 可以替代 Redux 吗?


通过上面的学习 ,我们发现即使是一个很简单的计数器应用,也要写大量的代码和使用繁琐的 API。

既然 ReactRedux 是使用 React 的 Context 来实现的,那我们只使用 Context 会怎么样呢?

对于小型项目,我更倾向于使用 Context。

但是对于大型项目和多人团队协作来说,Redux 有它不可替代的一些优势:

  • 更清晰的代码组织结构。
  • 更易于测试。
  • 提供了功能强大的 devtools。
  • 强大的生态系统。



相关文章
|
2月前
|
SQL 关系型数据库 MySQL
创建SQL数据库的基本步骤与代码指南
在信息时代,数据管理显得尤为重要,其中数据库系统已成为信息技术架构的关键部分。而当我们谈论数据库系统时,SQL(结构化查询语言)无疑是其中最核心的工具之一。本文将详细介绍如何使用SQL创建数据库,包括编写相应的代码和必要的步骤。由于篇幅限制,本文可能无法达到您要求的2000字长度,但会尽量涵盖创建数
91 3
|
4月前
|
人工智能 IDE 开发工具
实验步骤
【8月更文挑战第22天】实验步骤。
107 1
|
4月前
|
Java Linux 开发工具
eft搭建详细步骤!
1、安装vmware 2、下载合适版本的centos并安装 稍后安装操作系统(安装第二个时把安装程序光盘映像文件ISO清空) 自定义硬件-内存4G-处理器2X2-网络适配器NAT-CD/DVD使用ISO映像 网络和主机名:主机名设置、开启以太网(安装好使用ip addr查看ip地址1-9-2开头的) root密码设置 3、安装xshell 使用ip addr看ip然后连接上 4、安装jdk yum search java|grep jdk yum install -y java-1.8.0-openjdk*
111 2
|
5月前
|
Java Spring
使用 `BindingResult` 的步骤
使用 `BindingResult` 的步骤
95 0
|
7月前
|
监控 搜索推荐 虚拟化
VMwarepro16安装完整流程——注意事项全部详解
VMwarepro16安装完整流程——注意事项全部详解
236 0
|
Java 网络安全
Kettle流程步骤与应用步骤(六)
Kettle流程步骤与应用步骤(六)
297 1
Kettle流程步骤与应用步骤(六)
|
开发工具 iOS开发 开发者
友盟分享和登录步骤
友盟分享和登录步骤
203 0
友盟分享和登录步骤
|
分布式计算 大数据 Spark
阶段练习_需求介绍和明确步骤 | 学习笔记
快速学习 阶段练习_需求介绍和明确步骤
111 0
阶段练习_需求介绍和明确步骤 | 学习笔记
|
C语言 C++ 前端开发