Redux Toolkit 快速使用(学习笔记)

安装 Redux Toolkit 和 React-Redux

添加 Redux Toolkit 和 React-Redux 依赖包到你的项目中:

npm install @reduxjs/toolkit react-redux

创建 Redux Store

创建 src/store/index.js 文件。从 Redux Toolkit 引入 configureStore API。我们从创建一个空的 Redux store 开始,并且导出它:

// src/store/index.js
import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: {}
})

为 React 注入 Redux Store

创建 store 后,便可以在 React 组件中使用它。 在 src/index.js 中引入我们刚刚创建的 store , 通过 React-Redux 的 <Provider><App> 包裹起来,并将 store 作为 prop 传入。

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from './store/index.js'
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

创建 Redux State Slice

创建 src/store/modules/counterStore.js 文件。在该文件中从 Redux Toolkit 引入 createSlice API。

创建 slice 需要一个字符串名称来标识切片、一个初始 state 以及一个或多个定义了该如何更新 state 的 reducer 函数。slice 创建后 ,我们可以导出 slice 中生成的 Redux action creatorsreducer 函数。

// src/store/modules/counterStore.js
import { createSlice } from '@reduxjs/toolkit'

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0
  },
  reducers: {
    increment: state => {
      // Redux Toolkit 允许我们在 reducers 写 "可变" 逻辑。它
      // 并不是真正的改变状态值,因为它使用了 Immer 库
      // 可以检测到“草稿状态“ 的变化并且基于这些变化生产全新的
      // 不可变的状态
      state.value += 1
    },
    decrement: state => {
      state.value -= 1
    },
    // 第二个参数action的payload属性接收来自组件中dispatch action的传参
    incrementByAmount: (state, action) => {
      state.value += action.payload
    }
  }
})
// 每个 case reducer 函数会生成对应的 Action creators
export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer

将 Slice Reducers 添加到 Store 中

下一步,我们需要从计数切片中引入 reducer 函数,并将它添加到我们的 store 中。通过在 reducer 参数中定义一个字段,我们告诉 store 使用这个 slice reducer 函数来处理对该状态的所有更新。

// src/store/index.js
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'

export default configureStore({
  reducer: {
    counter: counterReducer
  }
})

在 React 组件中使用 Redux 状态和操作

现在我们可以使用 React-Redux 钩子让 React 组件与 Redux store 交互。我们可以使用 useSelector 从 store 中读取数据,使用 useDispatch dispatch actions。

import { useSelector, useDispatch } from 'react-redux';
import {
  decrement,
  increment,
  incrementByAmount,
} from './store/modules/counterStore.js';

export default function ReduxCounter() {
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();
  return (
    <div>
      <button onClick={() => dispatch(decrement())}>-</button>
      {count}
      <button onClick={() => dispatch(increment())}>+</button>
      {/* dispatch action传递的参数会在reducer函数的第二个参数action.payload进行接收 */}
      <button onClick={() => dispatch(incrementByAmount(10))}>add 10</button>
    </div>
  );
}

用 Thunk 编写异步逻辑

到目前为止,我们应用程序中的所有逻辑都是同步的。首先 dispatch action,store 调用 reducer 来计算新状态,然后 dispatch 函数完成并结束。但是,JavaScript 语言有很多编写异步代码的方法,我们的应用程序通常具有异步逻辑,比如从 API 请求数据之类的事情。我们需要一个地方在我们的 Redux 应用程序中放置异步逻辑。

thunk 是一种特定类型的 Redux 函数,可以包含异步逻辑。Thunk 是使用两个函数编写的:

  • 一个内部 thunk 函数,它以 dispatch 和 getState 作为参数
  • 外部创建者函数,它创建并返回 thunk 函数

比如我们从 counterStore 导出一个函数incrementAsync,incrementAsync就是一个 thunk action creator。

// 下面这个函数就是一个 thunk ,它使我们可以执行异步逻辑
// 你可以 dispatched 异步 action `dispatch(incrementAsync(10))` 就像一个常规的 action
// 调用 thunk 时接受 `dispatch` 函数作为第一个参数
// 当异步代码执行完毕时,可以 dispatched actions
export const incrementAsync = amount => dispatch => {
  setTimeout(() => {
    dispatch(incrementByAmount(amount))
  }, 1000)
}

我们可以像使用普通 Redux action creator 一样使用它们:

store.dispatch(incrementAsync(5))

但是,使用 thunk 需要在创建时将 redux-thunk middleware(一种 Redux 插件)添加到 Redux store 中。幸运的是,Redux Toolkit 的 configureStore 函数已经自动为我们配置好了,所以我们可以继续在这里使用 thunk。

当你需要进行 AJAX 调用以从服务器获取数据时,你可以将该调用放入 thunk 中。这是一个写得有点长的例子,所以你可以看到它是如何定义的:

// 外部的 thunk creator 函数
const fetchUserById = userId => {
  // 内部的 thunk 函数
  return async (dispatch, getState) => {
    try {
      // thunk 内发起异步数据请求
      const user = await userAPI.fetchById(userId)
      // 但数据响应完成后 dispatch 一个 action
      dispatch(userLoaded(user))
    } catch (err) {
      // 如果过程出错,在这里处理
    }
  }
}

dispatch thunk action creator

 useEffect(() => {
    dispatch(fetchUserById(5));
 }, [dispatch]);

总结

我们可以使用 Redux Toolkit configureStore API 创建一个 Redux store
  • configureStore 接收 reducer 函数来作为命名参数
  • configureStore 自动使用默认值来配置 store
在 slice 文件中编写 Redux 逻辑
  • 一个 slice 包含一个特定功能或部分的 state 相关的 reducer 逻辑和 action
  • Redux Toolkit 的 createSlice API 为你提供的每个 reducer 函数生成 action creator 和 action 类型
Redux reducer 必须遵循以下原则
  • 必须依赖 state 和 action 参数去计算出一个新 state
  • 必须通过拷贝旧 state 的方式去做 不可变更新 (immutable updates)
  • 不能包含任何异步逻辑或其他副作用
  • Redux Toolkit 的 createSlice API 内部使用了 Immer 库才达到表面上直接修改("mutating")state 也实现不可变更新(immutable updates)的效果
一般使用 “thunks” 来开发特定的异步逻辑
  • Thunks 接收 dispatch 和 getState 作为参数
  • Redux Toolkit 内置并默认启用了 redux-thunk 中间件
使用 React-Redux 来做 React 组件和 Redux store 的通信
  • 在应用程序根组件包裹 <Provider store={store}> 使得所有组件都能访问到 store
  • 全局状态应该维护在 Redux store 内,局部状态应该维护在局部 React 组件内
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容