Redux-toolkit的使用

448 阅读3分钟

安装

yarn add @reduxjs/toolkit react-redux

安装 redux 开发工具 redux-devtools

yarn add redux-devtools -D

基本使用

src 中创建一个 store 文件,在 store 中创建 features 文件用来存放模块的数据

image.png

  1. 创建 counterSlice
import { createSlice } from "@reduxjs/toolkit"

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 1,
    title: 'redux toolkit pre'
  },
  reducers: {
    increment(state, action) {
      // 内置了immutable
      state.count = state.count + 1
    },
    decrement(state) {
      state.count -= 1
    }
  }
})

// 下面的actions与reducers中的对应
export const { increment, decrement } = counterSlice.actions

// 下面的reducer是暴露出去的initialState
export default counterSlice.reduce
  1. storeindex.js 中进行合并
import { configureStore } from "@reduxjs/toolkit";

import counterSlice from "./features/counterSlice";
import recommendSlice from "./features/recommendSlice";

const store = configureStore({
  reducer: {
    counter: counterSlice,
    recommend: recommendSlice
  }
})

export default store
  1. 在全局的 index.js 中将 store 全局共享
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

import '@/assets/css/reset.css';

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

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);
  1. 在组件中使用

    下面的 state.counter 对应到 storeindexstore.counter ,最终拿到 counterSliceinitialState

import React, { memo } from 'react'
import { useDispatch, useSelector } from 'react-redux'

import { increment, decrement } from '@/store/features/counterSlice'

const Counter = memo(() => {
  const { count } = useSelector(state => state.counter)
  const dispatch = useDispatch()

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={e => dispatch(increment())}>+1</button>
      <button onClick={e => dispatch(decrement())}>-1</button>
    </div>
  )
})

export default Counter

传递参数

参数可以在 dispatch 中进行传递,如下

import React, { memo, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'

import { increment, decrement } from '@/store/features/counterSlice'

const SxRecommend = memo(() => {
  const { count } = useSelector(state => state.counter)

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={e => dispatch(increment({ step: 5 }))}>+1</button>
      <button onClick={e => dispatch(decrement())}>-1</button>
    </div>
  )
})

export default SxRecommend

reducers 中定义的函数中的 action 参数中拿到传递过来的参数

image.png

import { createSlice } from "@reduxjs/toolkit"

export const counterSlice = createSlice({
	。。。
  reducers: {
    increment(state, action) {
      console.log(action);
      // 内置了immutable
      state.count = state.count + action.payload.step
    }
  }
})

。。。

也可以进行解构

increment(state, { payload }) {
	state.count = state.count + payload.step
}

extraReducers

extraReducers 可以让在某个模块中触发其他模块的函数,并执行该函数时对本模块的数据进行操作,也可以用来操作异步请求(请看下面的异步请求)

如下:在 recommendSlice 模块执行 counterSlice 中的 increment 函数,并将本身的 topBanners 数据赋值为 increment 的参数

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import request from '@/services/request'

import { increment } from "./counterSlice";

export const getTopBanners = createAsyncThunk(
  'getTopBanners',
  async () => {
    return await request({ url: '/banner' })
  }
)

export const recommendSlice = createSlice({
  name: 'recommend',
  initialState: {
    topBanners: []
  },
  reducers: {},
  extraReducers: {
    [increment]: (state, action) => {
      state.topBanners = action.payload.step
    },
    [getTopBanners.fulfilled]: (state, { payload }) => {
      return state = { ...state, topBanners: payload.banners }
    }
  }
})

export default recommendSlice.reducer

异步请求

createAsyncThunk

createAsyncThunk 可以帮助我们创建一个异步函数,并且会给函数定义与 Promise 一样的三种状态: pendingfulfilledrejected

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import request from '@/services/request'

import { increment } from "./counterSlice";

export const getTopBanners = createAsyncThunk(
  'getTopBanners',
  async () => {
    return await request({ url: '/banner' })
  }
)

export const recommendSlice = createSlice({
  name: 'recommend',
  initialState: {
    topBanners: []
  },
  reducers: {},
  extraReducers: {
    [getTopBanners.pending](state, action) {
      console.log('进行中', state);
    },
    [getTopBanners.fulfilled]: (state, action) => {
      console.log('请求成功', state);
      return state = { ...state, topBanners: action.payload.banners }
    },
    [getTopBanners.rejected]: (state, action) => {
      console.log('请求失败', state);
    }
  }
})

export default recommendSlice.reducer

基本流程

  1. features 中创建 recommendSlice 文件

    • getTopBanners 请求完成后的数据会作为参数 action 传递给 extraReducers 中对应的函数,也可以进行解构
    • 如果不使用 async ,会把 then 中的 return res 传递给extraReducers 中对应的函数
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import request from '@/services/request'

export const getTopBanners = createAsyncThunk(
  'getTopBanners',
  async () => {
    return await request({ url: '/banner' })
  }
)

export const recommendSlice = createSlice({
  name: 'recommend',
  initialState: {
    topBanners: []
  },
  reducers: {},
  extraReducers: {
    [getTopBanners.fulfilled]: (state, action) => {
			console.log(action);
      return state = { ...state, topBanners: action.payload.banners }
    }
  }
})

export default recommendSlice.reducer
  1. index 中进行合并
import { configureStore } from "@reduxjs/toolkit";

import counterSlice from "./features/counterSlice";
import recommendSlice from "./features/recommendSlice";

const store = configureStore({
  reducer: {
    counter: counterSlice,
    recommend: recommendSlice
  }
})

export default store
  1. store 全局共享
  2. 在组件中使用
import React, { memo, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux' 

import { getTopBanners } from '@/store/features/recommendSlice'

const SxRecommend = memo(() => {
  const { topBanners } = useSelector(state => state.recommend)
  const dispatch = useDispatch()
  useEffect(() => {
    dispatch(getTopBanners())
  }, [dispatch])

  return (
    <div>
      <h2>SxRecommend</h2>
      <div>
        {
          topBanners.map((item, index) => {
            return <img key={item.imageUrl} src={item.imageUrl} />
          })
        }
      </div>
    </div>
  )
})

export default SxRecommend

也可以把异步请求函数抽出来放到 services 模块进行管理,使用时直接导入即可

import request from './request'
import { createAsyncThunk } from "@reduxjs/toolkit";

export const getTopBanners = createAsyncThunk(
  'getTopBanners',
  async () => {
    return await request({ url: '/banner' })
  }
)