redux以及toolkit工具的状态管理详解 (redux官网推荐方案)

2,445 阅读5分钟

Redux是一个强大的JavaScript状态管理库,它被广泛应用于React和其他前端框架。然而,Redux的繁琐和冗长的代码编写方式一直以来都是开发者们所诟病的。为了解决这个问题,Redux官方推出了Redux Toolkit,它是一个开箱即用的工具集,旨在简化Redux的使用并提供更好的开发体验。本篇博客将带您深入了解Redux Toolkit;

下载使用

npm install @reduxjs/toolkit react-redux

redux单独的使用

为了方便大家去理解,我就把redux创建全写一个文件了;

import { createStore } from "redux";

const ADD_NUM = 'add'

export const add = num => ({
  type: ADD_NUM,
  payload: { num }
})

const initState = {
    count: 0,
}

export const countReducer = (state = initState, action) => {
  switch (action.type) {
    case ADD_NUM:
      return {
         count: state.count + action.payload.num
      }
    default:
      return state
  }
}

const store = createStore(countReducer)

export default store

这样,一个完整的状态管理仓库就创建好了,接下来就是使用react的Provider组件进行注册了;

import App from './App.jsx';
import { Provider } from 'react-redux'
import store from './store'

const Application = (
    <Provider store={store}>
        <App />
    </Provider>
)

结下来就是咋们的使用环节了 方式1:使用store中的getState()获取值

// 方式1
function App () {
    // counter 不是响应式的
    const counter = store.getState().counter
    return <div>值:{{counter}}</div>
}

方法2:使用react-redux的useSelector

import { useSelector } from 'react-redux';

function App() {
    // counter 是响应式的
    const counter = useSelector(state =>  state.counter);
    return <div>值:{counter}</div>;
}

方法3:使用react-redux的高阶组件connect

import { connect } from 'react-redux';

function App({ counter }) {
    // counter 是响应式的
    return <div>值:{counter}</div>;
}

export default connect(state => ({
    counter: state.counter,
}))(App);

dispatch派发action

dispatch 是 Redux 中用于派发(触发) action 的函数。在 Redux 中,通过派发 action 来改变应用的状态。dispatch 函数接受一个 action 对象作为参数,然后将该 action 发送到 Redux Store 中,触发相应的 reducer 处理状态更新

import { connect,useDispatch } from 'react-redux';
import { add } from '{上面创建redux仓库的文件地址}';

function App({ counter }) {
    const dispatch = useDispatch();
    const add = () => {
        dispatch(add(1))
    }
    return <div>
        <span>值:{counter}</span>
        <button onClick={add}>加1</button>
    </div>;
}
export default connect(state => ({
    counter: state.counter,
}))(App);

在上面这段代码中,我们从useDispatch获取到了dispatch,通过dispatch派发action去修改状态,这样,我们就实现了派发;

上面代码运行的效果:点击【加1】按钮,span标签里面显示的counter就会加一;

异步操作

dispatch函数默认是同步的,一般情况下,是不建议在异步中去使用dispatch,否由于异步操作的执行时间不确定,如果在异步操作完成之前多次调用 dispatch,可能会导致多个相同或不同的 action 同时在处理,这可能会导致状态的混乱和不可预测的结果。

为了去支持异步调用dispatch,我们可以使用异步中间件redux-thunk,结下来我们使用redux-thunk对前面的状态管理仓库进行改造

import { createStore, applyMiddleware } from "redux";
import thunkMiddleware from 'redux-thunk';
const ADD_NUM = 'add'

export const add = num => ({
  type: ADD_NUM,
  payload: { num }
})

export const asyncDouble = (num) => {
  return async (dispatch, getState) => {
    const state = getState();
    await new Promise((resolve, reject) => {
      setTimeout(() => {
        dispatch(add(state.count + num));
        resolve();
      }, 1000);
    });
  };
};

const initState = {
    count: 0,
}

export const countReducer = (state = initState, action) => {
  switch (action.type) {
    case ADD_NUM:
      return {
         count: state.count + action.payload.num
      }
    default:
      return state
  }
}

const store = createStore(countReducer, applyMiddleware(thunkMiddleware))

export default store

在上面我们加入的redux-thunk中间件,然后定义了asyncDouble的异步方法,接下来使用这个异步函数

import { connect,useDispatch } from 'react-redux';
import { add } from '{上面创建redux仓库的文件地址}';

function App({ counter }) {
    const dispatch = useDispatch();
    const add = () => {
        dispatch(asyncDouble(1))
    }
    return <div>
        <span>值:{counter}</span>
        <button onClick={add}>加1</button>
    </div>;
}
export default connect(state => ({
    counter: state.counter,
}))(App);

这样,我们就完成了异步的调用;但是为什么这样调用就会有效果了呢?

因为redux-thunk中间件会检查 asyncDouble 返回的值。如果返回的是一个函数而不是一个普通的 action 对象,redux-thunk 会将该函数作为参数调用,并传递 dispatch 和 getState 两个函数。这样,我们就可以在返回的函数中执行异步操作;

redux的模块化

import { createStore, combineReducers } from 'redux';
import module1Reducer from './module1/reducer';
import module2Reducer from './module2/reducer';

const rootReducer = combineReducers({
  module1: module1Reducer,
  module2: module2Reducer,
});

const store = createStore(rootReducer);
export default store;

使用

import { connect } from 'react-redux';

function App({ counter }) {
    return <div>值:{counter}</div>;
}

export default connect(state => ({
    counter: state.module1.counter,
}))(App);

redux配合toolkit的使用

基于toolkit创建一个状态管理仓库

// /store/counter.js
import { createSlice } from '@reduxjs/toolkit'

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0
  },
  reducers: {
    add: state => {
      state.value += 1
    },
    reducer: state => {
      state.value -= 1
    },
  }
})
// 反回派生事件
export const { add, reducer } = counterSlice.actions

export default counterSlice.reducer

createSlice: createSlice 需要一个字符串名称来标识切片[模块]、一个初始 state 以及一个或多个定义了该如何更新 state 的 reducer 函数。切片创建后 ,我们可以导出切片中生成的Redux派发函数 add和reducer。

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

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

注册store

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

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

状态的使用派生事件的使用基本和上面的案例是一样的; 在toolkit中默认使用redux-thunk作为默认的异步处理中间件;所以在toolkit中的异步处理也基本上和上面的案例是一样的

createAsyncThunk函数

export const fetchPosts = createAsyncThunk('counter/add', async () => {
  const response = await client.get('/api/add')
  return response.data
})

createAsyncThunk 接收 2 个参数:

第一个将用作生成的 action 类型的前缀的字符串【一般情况下为:模块名/该模块中reducers的键名】 第二个是一个回调函数,它应该返回一个包含一些数据的 Promise,或者一个被拒绝的带有错误的 Promise

大家都看到这了,说明你已经理解怎么去使用redux以及toolkit了,创作不易,求求给个赞吧!🥺🥺🥺