npm install redux redux-logger redux-thunk @reduxjs/toolkit express cors axios --save
public\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>Redux Toolkit</title>
</head>
<body>
<div>
<p id="value">0</p>
<button id="add">+</button>
<button id="minus">-</button>
</div>
</body>
</html>
src\index.js
import { createStore } from 'redux';
const ADD = 'ADD'
const MINUS = 'MINUS'
function add() {
return { type: ADD }
}
function minus() {
return { type: MINUS }
}
function counter(state = { number: 0 }, action) {
switch (action.type) {
case ADD:
return {number:state.number+1}
case MINUS:
return {number:state.number-1}
default:
return state
}
}
var store = createStore(counter)
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().number;
}
render()
store.subscribe(render)
document.getElementById('add').addEventListener('click', function () {
store.dispatch(add())
})
document.getElementById('minus').addEventListener('click', function () {
store.dispatch(minus())
})
const ADD = 'ADD'
冗余switch
结构不清晰configureStore()
函数,其中覆盖了 createStore()
的功能configureStore() 函数
提供简化的配置选项。它可以自动组合切片 slice 的 reducer,添加你提供的任何 Redux 中间件,默认
情况下包含 redux-thunk,并启用Redux DevTools 扩展<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>Redux Toolkit</title>
</head>
<body>
<div>
<p id="value">0</p>
<button id="add">+</button>
<button id="minus">-</button>
+ <button id="async-add">async-add</button>
</div>
</body>
</html>
src\index.js
-import { createStore } from 'redux';
+import {configureStore} from '@reduxjs/toolkit';
+import {configureStore} from './toolkit';
+import thunk from 'redux-thunk';
+import logger from 'redux-logger';
const ADD = 'ADD'
const MINUS = 'MINUS'
function add() {
return { type: ADD }
}
function minus() {
return { type: MINUS }
}
function counter(state = { number: 0 }, action) {
switch (action.type) {
case ADD:
return {number:state.number+1}
case MINUS:
return {number:state.number-1}
default:
return state
}
}
-let store = createStore(counter)
+const store = configureStore({
+ reducer: counter,
+ middleware: [thunk, logger]
+})
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().number;
}
render()
store.subscribe(render)
document.getElementById('add').addEventListener('click', function () {
store.dispatch(add())
})
document.getElementById('minus').addEventListener('click', function () {
store.dispatch(minus())
})
+document.getElementById('async-add').addEventListener('click', function () {
+ store.dispatch((dispatch)=>{
+ setTimeout(()=>{
+ dispatch(add())
+ },1000)
+ })
+})
src\toolkit\index.js
export { default as configureStore } from './configureStore';
src\toolkit\configureStore.js
import { combineReducers,applyMiddleware,createStore,compose} from 'redux';
function isPlainObject(value) {
if (typeof value !== "object" || value === null)
return false;
return Object.getPrototypeOf(value) === Object.prototype;
}
function configureStore(options = {}) {
let { reducer, middleware, preloadedState } = options;
let rootReducer;
if (typeof reducer === "function") {
rootReducer = reducer;
} else if (isPlainObject(reducer)) {
rootReducer = combineReducers(reducer);
}
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return createStore(rootReducer, preloadedState, composeEnhancers(enhancer));
}
export default configureStore;
compose
function add1(str){
return str+1;
}
function add2(str){
return str+2;
}
function compose(fn1,fn2){
return function(str){
return fn1(fn2(str))
}
}
let fn = compose(add1, add2);
let result = fn('zhufeng');
console.log(result);//zhufeng21
src\index.js
+import {configureStore,createAction} from './toolkit';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
-const ADD = 'ADD'
-const MINUS = 'MINUS'
-function add() {
- return { type: ADD }
-}
+const add = createAction('ADD')
-function minus() {
- return { type: MINUS }
-}
+const minus = createAction('MINUS', (amount) => ({ payload: amount }))
+console.log(minus.toString());
+console.log(minus.type);
function counter(state = { number: 0 }, action) {
switch (action.type) {
+ case add.type:
return {number:state.number+1}
+ case minus.type:
+ return {number:state.number-action.payload}
default:
return state
}
}
const store = configureStore({
reducer: counter,
middleware: [thunk, logger]
})
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().number;
}
render()
store.subscribe(render)
document.getElementById('add').addEventListener('click', function () {
store.dispatch(add())
})
document.getElementById('minus').addEventListener('click', function () {
+ store.dispatch(minus(2))
})
document.getElementById('async-add').addEventListener('click', function () {
store.dispatch((dispatch)=>{
setTimeout(()=>{
dispatch(add())
},1000)
})
})
src\toolkit\index.js
export { default as configureStore } from './configureStore';
+export { default as createAction } from './createAction';
src\toolkit\createAction.js
function createAction(type, prepareAction) {
function actionCreator(...args) {
if (prepareAction) {
var prepared = prepareAction.apply(null, args);
return {
type: type,
payload: prepared.payload,
error: prepared.error
};
}
return {
type: type,
payload: args[0]
};
}
actionCreator.toString = function () {
return "" + type;
}
actionCreator.type = type;
return actionCreator;
}
export default createAction;
src\index.js
import {configureStore,createAction,createReducer} from './toolkit';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
const add = createAction('ADD')
const minus = createAction('MINUS', (amount) => ({ payload: amount }))
console.log(minus.toString());
console.log(minus.type);
-function counter(state = { number: 0 }, action) {
- switch (action.type) {
- case add.type:
- return {number:state.number+1}
- case minus.type:
- return {number:state.number-action.payload}
- default:
- return state
- }
-}
+const counter = createReducer({number:0}, {
+ [add]: state => ({number:state.number+1}),
+ [minus]: state => ({number:state.number-1})
+})
const store = configureStore({
reducer: counter,
middleware: [thunk, logger]
})
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().number;
}
render()
store.subscribe(render)
document.getElementById('add').addEventListener('click', function () {
store.dispatch(add())
})
document.getElementById('minus').addEventListener('click', function () {
store.dispatch(minus(2))
})
document.getElementById('async-add').addEventListener('click', function () {
store.dispatch((dispatch)=>{
setTimeout(()=>{
dispatch(add())
},1000)
})
})
src\toolkit\createReducer.js
function createReducer(initialState, reducers={}) {
return function (state = initialState, action) {
let reducer = reducers[action.type];
if (reducer) return reducer(state, action);
return state;
}
}
export default createReducer;
src\toolkit\index.js
export { default as configureStore } from './configureStore';
export { default as createAction } from './createAction';
+export { default as createReducer } from './createReducer';
分片
对象,该对象包含生成的 reducer 函数作为一个名为 reducer 的字段,以及在一个名为 actions 的对象中生成的 action creator//import {configureStore,createAction,createReducer,createSlice} from '@reduxjs/toolkit';
import {configureStore,createAction,createReducer,createSlice} from './toolkit';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
-const add = createAction('ADD')
-const minus = createAction('MINUS', (amount) => ({ payload: amount }))
-const counter = createReducer({number:0}, {
- [add]: state => ({number:state.number+1}),
- [minus]: state => ({number:state.number-1})
-})
+const counterSlice = createSlice({
+ name: 'counter',
+ initialState: {number:0},
+ reducers: {
+ add: (state) => ({number:state.number+1}),//派发的时候动作类型是 counter/add
+ minus: (state,action) => ({number:state.number-action.payload})
+ }
+})
const { actions, reducer } = counterSlice
console.log(actions);
const { add, minus } = actions
console.log(add);
const store = configureStore({
reducer: reducer,
middleware: [thunk, logger]
})
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().number;
}
render()
store.subscribe(render)
document.getElementById('add').addEventListener('click', function () {
store.dispatch(add())
})
document.getElementById('minus').addEventListener('click', function () {
store.dispatch(minus(2))
})
document.getElementById('async-add').addEventListener('click', function () {
store.dispatch((dispatch)=>{
setTimeout(()=>{
dispatch(add())
},1000)
})
})
src\toolkit\createSlice.js
import { createReducer, createAction } from './'
function createSlice(options) {
let { name, initialState={}, reducers={} } = options;
let actions = {};
const prefixReducers = {};
Object.keys(reducers).forEach(function (key) {
var type = getType(name, key);
actions[key] = createAction(type);
prefixReducers[type]=reducers[key];
})
let reducer = createReducer(initialState, prefixReducers);
return {
name,
reducer,
actions
};
}
function getType(slice, actionKey) {
return slice + "/" + actionKey;
}
export default createSlice;
src\toolkit\index.js
export { default as configureStore } from './configureStore';
export { default as createAction } from './createAction';
export { default as createReducer } from './createReducer';
+export { default as createSlice } from './createSlice';
let produce = require('immer').default;
let baseState = {
ids: [1],
pos: {
x: 1,
y: 1
}
}
let nextState = produce(baseState, (draft) => {
draft.ids.push(2);
})
console.log(baseState.ids === nextState.ids);//false
console.log(baseState.pos === nextState.pos);//true
src\index.js
//import {configureStore,createAction,createReducer,createSlice} from '@reduxjs/toolkit';
import {configureStore,createAction,createReducer,createSlice} from './toolkit';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
const counterSlice = createSlice({
name: 'counter',
initialState: {number:0},
reducers: {
+ add: (state) => state.number+=1,//派发的时候动作类型是 counter/add
+ minus: (state,action) => state.number-=action.payload
}
})
const { actions, reducer } = counterSlice
console.log(actions);
const { add, minus } = actions
console.log(add);
const store = configureStore({
reducer: reducer,
middleware: [thunk, logger]
})
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().number;
}
render()
store.subscribe(render)
document.getElementById('add').addEventListener('click', function () {
store.dispatch(add())
})
document.getElementById('minus').addEventListener('click', function () {
store.dispatch(minus(2))
})
document.getElementById('async-add').addEventListener('click', function () {
store.dispatch((dispatch)=>{
setTimeout(()=>{
dispatch(add())
},1000)
})
})
src\toolkit\createReducer.js
+import produce from 'immer';
function createReducer(initialState, reducers={}) {
return function (state = initialState, action) {
let reducer = reducers[action.type];
+ if (reducer)
+ return produce(state, draft => {
+ reducer(draft, action);
+ });
return state;
}
}
export default createReducer;
///const {createSelector} = require('reselect');
function createSelector(selectors, reducer) {
let lastState;
let lastValue;
return function (state) {
if (lastState === state) {
return lastValue;
}
let values = selectors.map(selector => selector(state));
lastValue = reducer(...values);
lastState = state;
return lastValue;
}
}
const selectCounter1 = state => state.counter1
const selectCounter2 = state => state.counter2
const totalSelector = createSelector(
[selectCounter1, selectCounter2],
(counter1, counter2) => {
console.log('计算结果');
return counter1.number + counter2.number;
}
)
let state = { counter1: { number: 1 }, counter2: { number: 2 } };
let state1 = totalSelector(state);
console.log(state1);
let state2 = totalSelector(state);
console.log(state2);
public\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>Redux Toolkit</title>
</head>
<body>
<div>
+ <p id="value1">0</p>
+ <button id="add1">add1</button>
+ <button id="minus1">minus1</button>
+ <hr/>
+ <p id="value2">0</p>
+ <button id="add2">add2</button>
+ <button id="minus2">minus2</button>
+ <hr/>
+ <p id="sum">0</p>
</div>
</body>
</html>
src\index.js
//import {configureStore,createAction,createReducer,createSlice} from '@reduxjs/toolkit';
import {configureStore,createAction,createReducer,createSlice,createSelector} from './toolkit';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
const counter1Slice = createSlice({
name: 'counter1',
initialState: { number: 0 },
reducers: {
add: state => { state.number += 1 },
minus: state => { state.number -= 1 }
}
})
const counter2Slice = createSlice({
name: 'counter2',
initialState: { number: 0 },
reducers: {
add: state => { state.number += 1 },
minus: state => { state.number -= 1 }
}
})
const { actions: { add: add1, minus: minus1 }, reducer: reducer1 } = counter1Slice
const { actions: { add: add2, minus: minus2 }, reducer: reducer2 } = counter2Slice
const store = configureStore({
reducer: { counter1: reducer1, counter2: reducer2 },
middleware: [thunk, logger]
})
var value1El = document.getElementById('value1')
var value2El = document.getElementById('value2')
var sumEl = document.getElementById('sum')
const selectCounter1 = state => state.counter1
const selectCounter2 = state => state.counter2
const totalSelector = createSelector(
[selectCounter1, selectCounter2],
(counter1, counter2) => {
return counter1.number + counter2.number;
}
)
function render() {
value1El.innerHTML = store.getState().counter1.number;
value2El.innerHTML = store.getState().counter2.number;
sumEl.innerHTML = totalSelector(store.getState());
}
render()
store.subscribe(render)
document.getElementById('add1').addEventListener('click', function () {
store.dispatch(add1())
})
document.getElementById('minus1').addEventListener('click', function () {
store.dispatch(minus1())
})
document.getElementById('add2').addEventListener('click', function () {
store.dispatch(add2())
})
document.getElementById('minus2').addEventListener('click', function () {
store.dispatch(minus2())
})
src\toolkit\index.js
export { default as configureStore } from './configureStore';
export { default as createAction } from './createAction';
export { default as createReducer } from './createReducer';
export { default as createSlice } from './createSlice';
+export {createSelector } from '../reselect';
src\reselect\index.js
export {default as createSelector} from './createSelector';
src\reselect\createSelector.js
function createSelector(selectors, reducer) {
let lastState;
let lastValue;
return function (state) {
if (lastState === state) {
return lastValue;
}
let values = selectors.map(selector => selector(state));
lastValue = reducer(...values);
lastState = state;
return lastValue;
}
}
export default createSelector;
src\index.js
import { configureStore, createSlice, createAsyncThunk } from './toolkit';
import axios from 'axios';
//接收redux动作类型字符串和一个返回promise回调的函数
//它会基于你传递的动作类型前缀生成promise生命周期的动作类型
//并且返回一个thunk动作创建者,这个thunk动作创建者会运行promise回调并且派发生命周期动作
export const getTodosList = createAsyncThunk(
"todos/list", async () => await axios.get(`http://localhost:8080/todos/list`)
);
const initialState = {
todos: [],
loading: false,
error: null,
};
const todoSlice = createSlice({
name: 'todo',
initialState,
reducers: {},
extraReducers: {
[getTodosList.pending]: (state) => {
state.loading = true;
},
[getTodosList.fulfilled]: (state, action) => {
state.todos = action.payload.data;
state.loading = false;
},
[getTodosList.rejected]: (state, action) => {
state.todos = [];
state.error = action.error.message;
state.loading = false;
}
}
})
const { reducer } = todoSlice;
const store = configureStore({
reducer
})
let promise = store.dispatch(getTodosList());
console.log('请求开始',store.getState());
//promise.abort();
promise.then((response)=>{
console.log('成功',response);
setTimeout(()=>{
console.log('请求结束',store.getState());
},);
},error=>{
console.log('失败',error);
setTimeout(()=>{
console.log('请求结束',store.getState());
},);
});
src\toolkit\configureStore.js
import { combineReducers,applyMiddleware,createStore,compose } from 'redux';
+import thunk from 'redux-thunk';
function isPlainObject(value) {
if (typeof value !== "object" || value === null)
return false;
return Object.getPrototypeOf(value) === Object.prototype;
}
function configureStore(options = {}) {
+ let { reducer, middleware=[thunk], preloadedState } = options;
let rootReducer;
if (typeof reducer === "function") {
rootReducer = reducer;
} else if (isPlainObject(reducer)) {
rootReducer = combineReducers(reducer);
}
const enhancer = applyMiddleware(...middleware);
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return createStore(rootReducer, preloadedState, composeEnhancers(enhancer));
}
export default configureStore;
src\toolkit\createReducer.js
import produce from 'immer';
+function createReducer(initialState, reducers={}, extraReducers={}) {
return function (state = initialState, action) {
let reducer = reducers[action.type];
if (reducer)
return produce(state, draft => {
reducer(draft, action);
});
+ let extraReducer = extraReducers[action.type];
+ if (extraReducer) {
+ return produce(state, draft => {
+ extraReducer(draft, action);
+ });
+ }
return state;
}
}
export default createReducer;
src\toolkit\createSlice.js
import { createReducer, createAction } from './'
function createSlice(options) {
+ let { name, initialState={}, reducers={},extraReducers={} } = options;
let actions = {};
const prefixReducers = {};
Object.keys(reducers).forEach(function (key) {
var type = getType(name, key);
actions[key] = createAction(type);
prefixReducers[type]=reducers[key];
})
+ let reducer = createReducer(initialState, prefixReducers,extraReducers);
return {
name,
reducer,
actions
};
}
function getType(slice, actionKey) {
return slice + "/" + actionKey;
}
export default createSlice;
src\toolkit\createAsyncThunk.js
import { createAction } from './';
function createAsyncThunk(typePrefix, payloadCreator) {
let pending = createAction(typePrefix + "/pending", function () {
return ({ payload: void 0 });
});
let fulfilled = createAction(typePrefix + "/fulfilled", function (payload) {
return ({ payload });
});
let rejected = createAction(typePrefix + "/rejected", function (error) {
return ({ error });
});
function actionCreator(arg) {
return function (dispatch) {
dispatch(pending());
const promise = payloadCreator(arg);
let abort;
const abortedPromise = new Promise((_, reject) => {
abort = () => {
reject({ name: "AbortError", message: "Aborted" });
}
});
Promise.race([promise, abortedPromise]).then(result => {
return dispatch(fulfilled(result));
}, (error) => {
return dispatch(rejected(error));
});
return Object.assign(promise, { abort });
}
}
return Object.assign(actionCreator, { pending, rejected, fulfilled });
}
export default createAsyncThunk;
src\toolkit\index.js
export { default as configureStore } from './configureStore';
export { default as createAction } from './createAction';
export { default as createReducer } from './createReducer';
export { default as createSlice } from './createSlice';
export {createSelector } from '../reselect';
+export { default as createAsyncThunk } from "./createAsyncThunk";
api.js
let express = require('express');
let cors = require('cors');
let app = express();
app.use(cors());
app.use((req,res,next)=>{
setTimeout(()=>{
if(Math.random()>.5){
next();
}else{
next('接口出错');
}
},1000);
});
let todos = [{id:1,text:"吃饭"},{id:2,text:"睡觉"}];
app.get('/todos/list',(_req,res)=>{
res.json(todos);
});
app.get('/todos/detail/:id',(req,res)=>{
let id = req.params.id;
let todo = todos.find(item=>item.id === parseInt(id));
res.json(todo);
});
app.listen(8080,()=>console.log(`服务在端口8080启动`));
根据用户的交互来管理缓存的生命周期
createApi() RTK Query的核心函数,它允许你定义endpoint的集合用来描述如何获取数据,包含如何获取和转换数据
src\index.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>Redux Toolkit</title>
</head>
<body>
+ <div id="root"></div>
</body>
</html>
src\index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
src\App.js
import todosApi from './todos'
//使用自定义查询 hook可以自动获取数据并且返回查询结果
function App() {
// 使用一个查询Hook,它会自动获取数据并且返回查询的值
//const { data, error, isLoading } = useGetTodosQuery(1)
const { data, error, isLoading } = todosApi.endpoints.getTodos.useQuery(1)
// Individual hooks are also accessible under the generated endpoints:
// 每个hook也
console.log('isLoading=', isLoading, 'error=', error, 'data=', data);
if(isLoading){
return <div>加载中....</div>;
}else{
if(error){
return <div>{error.error}</div>;
}else if(data){
return <div>{data.text}</div>;
}else{
return null;
}
}
}
export default App;
src\store.js
import { configureStore } from '@reduxjs/toolkit'
//import { configureStore } from './toolkit'
import todosApi from './todos'
//API slice会包含自动生成的redux reducer和一个自定义中间件
const store = configureStore({
reducer: {
[todosApi.reducerPath]: todosApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(todosApi.middleware)
})
export default store;
src\todos.js
//React entry point 会自动根据endpoints生成hooks
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
//import { createApi, fetchBaseQuery } from './toolkit/query/react'
//使用base URL 和endpoints 定义服务
const todosApi = createApi({
reducerPath: 'todosApi',
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:8080' }),
endpoints: (builder) => {
return {
//从参数生成查询参数 转变响应并且缓存
getTodos: builder.query({query: (id) => `/todos/detail/${id}`}),
}
}
})
//导出可在函数式组件使用的hooks,它是基于定义的endpoints自动生成的
//export const { useGetTodosQuery } = todosApi
export default todosApi;
src\toolkit\configureStore.js
import { combineReducers,applyMiddleware,createStore,compose } from 'redux';
import thunk from 'redux-thunk';
function isPlainObject(value) {
if (typeof value !== "object" || value === null)
return false;
return Object.getPrototypeOf(value) === Object.prototype;
}
function configureStore(options = {}) {
let { reducer, middleware=[thunk], preloadedState } = options;
let rootReducer;
if (typeof reducer === "function") {
rootReducer = reducer;
} else if (isPlainObject(reducer)) {
rootReducer = combineReducers(reducer);
}
+ middleware=typeof middleware === 'function'?middleware(()=>[thunk]):middleware
const enhancer = applyMiddleware(...middleware);
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return createStore(rootReducer, preloadedState, composeEnhancers(enhancer));
}
export default configureStore;
src\toolkit\query\react.js
import { createSlice } from '../'
import { useEffect, useContext, useReducer } from 'react';
import { ReactReduxContext } from 'react-redux';
const FETCH_DATA = 'FETCH_DATA';
function fetchBaseQuery({ baseUrl }) {
return async function (url) {
url = baseUrl + url;
let data = await fetch(url).then(res => res.json());
return data;
}
}
function createApi({ reducerPath, baseQuery, endpoints }) {
let builder = {
query(options) {
function useQuery(id) {
const { store } = useContext(ReactReduxContext)
const [, forceUpdate] = useReducer(x => x + 1, 0);
useEffect(() => {
let url = options.query(id);
store.dispatch({ type: FETCH_DATA, payload: { url } });
return store.subscribe(forceUpdate);
}, [id, store])
let state = store.getState();
return state ? state[reducerPath] : {};
}
return { useQuery };
}
}
let slice = createSlice({
name: reducerPath,
initialState: { data: null, error: null, isLoading: false },
reducers: {
setValue(state, { payload = {} }) {
for (let key in payload)
state[key] = payload[key];
}
}
});
const { actions, reducer } = slice
let api = {
reducerPath,
endpoints: endpoints(builder),
reducer,
middleware: function ({ dispatch }) {
return function (next) {
return function (action) {
if (action.type === FETCH_DATA) {
let { url } = action.payload;
; (async function () {
try {
dispatch(actions.setValue({ isLoading: true }));
let data = await baseQuery(url);
dispatch(actions.setValue({ data, isLoading: false }));
} catch (error) {
console.log(error);
console.log(typeof error);
dispatch(actions.setValue({ error: { error: error.toString() }, isLoading: false }));
}
})();
} else {
next(action);
}
}
}
}
}
return api;
}
export { fetchBaseQuery, createApi }
src\todos.js
//React entry point 会自动根据endpoints生成hooks
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import axios from 'axios'
axios.interceptors.response.use(function (response) {
return {data:response.data};//成功的响应体
},function (error){//失败
return {error:{error:error.message}};
});
const axiosBaseQuery = ({ baseUrl }) => (
async (url) => {
try {
const result = await axios({ url: baseUrl + url })
return result;
} catch (error) {
return error;
}
}
)
//import { createApi, fetchBaseQuery } from './toolkit/query/react'
//使用base URL 和endpoints 定义服务
const todosApi = createApi({
reducerPath: 'todosApi',
baseQuery: axiosBaseQuery({ baseUrl: 'http://localhost:8080' }),
endpoints: (builder) => {
return {
//从参数生成查询参数 转变响应并且缓存
getTodos: builder.query({query: (id) => `/todos/detail/${id}`}),
}
}
})
//导出可在函数式组件使用的hooks,它是基于定义的endpoints自动生成的
//export const { useGetTodosQuery } = todosApi
export default todosApi;