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;