Redux-Toolkit

萧焱
2023-12-01

Redux-Toolkit


一个官方提供用于Redux高效开发的、有想法的、功能齐全的工具包

#安装
npm i @reduxjs/toolkit
#or
yarn add @reduxjs/toolkit
yarn add react-redux # 安装插件
yarn add redux-devtools -D # 安装调试工具,-D安装开发依赖



Redux-Toolkit 的使用

// store.js

import { configureStore } from '@reduxjs/toolkit';
import counterSlice from './features/counterSlice';
import movieSlice from './features/movieSlice';

// configureStore创建一个redux数据
export default configureStore({
    reducer: {
        counter: counterSlice,
        movie: movieSlice,
    },
});

创建store

redux-toolkit内置了thunk插件,不再需要单独安装,可以直接处理异步的action


// slice.js

import { createSlice } from '@reduxjs/toolkit';

export const counterSlice = createSlice({
    name: 'counter', // 命名空间,在调用action的时候会默认的设置为action的前缀
    // 初始值
    initialState: {
        count: 1,
        title: 'redux toolkit pre',
    },
    // 这里的属性会自动的导出为actions,在组件中可以直接通过dispatch进行触发
    reducers: {
        increment (state, { payload }) {
            // console.log(action);
            state.count = state.count + payload.step; // 内置了immutable
        },
        decrement (state) {
            state.count -= 1;
        },
    },
});

// 导出actions
export const { increment, decrement } = counterSlice.actions;

// 内置了thunk插件,可以直接处理异步请求
export const asyncIncrement = (payload) => (dispatch) => {
    setTimeout(() => {
        dispatch(increment(payload));
    }, 2000);
};

export default counterSlice.reducer; // 导出reducer,在创建store时使用到

使用createSlice方法创建一个slice,每一个slice里面包含了reducer和actions,可以实现模块化的封装

所有的相关操作都独立在一个文件中完成。

关键属性:
(1)name 命名空间
可以自动的把每一个action进行独立,解决了action的type出现同名的文件。在使用的时候默认会把使用name/actionName

(2)initialState
state数据的初始值

(3)reducers
定义的action。由于内置了immutable插件,可以直接使用赋值的方式进行数据的改变,不需要每一次都返回一个新的state数据。






项目中使用

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

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

// 在组件内部,使用useState和useDispatch可以直接获取state数据与dispatch方法
import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, asyncIncrement } from './store/features/counterSlice'; // 引入actions

function App () {
    const { count } = useSelector((state) => state.counter);
    const dispatch = useDispatch();
    return (
        <div className='App'>
            <button
                onClick={() => {
                    dispatch(increment({ step: 2 })); // dispatch派发action
                }}
            >
                {count}
            </button>
            <hr />
            <button
                onClick={() => {
                    dispatch(asyncIncrement({ step: 1 }));
                }}
            >
                {count}
            </button>
        </div>
    );
}

export default App;



创建异步action

createAsyncThunk方法可以创建一个异步的action

这个方法被执行的时候会有三个( pending(进行中) fulfilled(成功) rejected(失败))状态

可以监听状态的改变执行不同的操作

以下代码示例中使用到了extraReducers创建额外的action对数据获取的状态信息进行监听

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
// createAsyncThunk创建一个异步的action,这个方法被触发的时候会有三个状态
// pending(进行中) fulfilled(成功) rejected(失败)

import { increment } from './counterSlice';

// 发起网络请求获取数据
const loadMoviesAPI = () =>
    fetch(
        'https://pcw-api.iqiyi.com/search/recommend/list?channel_id=1&data_type=1&mode=11&page_id=2&ret_num=48'
    ).then((res) => res.json());

// 这个action是可以直接调用的,用来处理异步操作获取数据
export const loadData = createAsyncThunk('movie/loadData', async () => {
    const res = await loadMoviesAPI();
    return res; // 此处的返回结果会在 .fulfilled中作为payload的值
});

export const movieSLice = createSlice({
    name: 'movie',
    initialState: {
        list: [],
        totals: 0,
    },
    reducers: {
        loadDataEnd (state, { payload }) {
            state.list = payload;
            state.totals = payload.length;
        },
    },
    // 可以额外的触发其他slice中的数据关联改变
    extraReducers: {
        [loadData.fulfilled] (state, { payload }) {
            console.log(payload);
            state.list = payload.data.list;
        },
        [loadData.rejected] (state, err) {
            console.log(err);
        },
        [loadData.pending] (state) {
            console.log('进行中');
        },
    },
});

export const { loadDataEnd } = movieSLice.actions;
export default movieSLice.reducer;
 类似资料: