16_Redux系列
什么是纯函数?
函数式编程中有一个非常重要的概念叫**纯函数,**纯函数的概念:
- 函数在获得相同的输入时,会产生相同的输出
- 函数的输出和输入值以外的其它状态无关,也和由I/O设备产生的外部输出无关
- 函数**不能有语义上可观察到的函数副作用,**如:事件触发、更改输出值以外的内容
总结:
- 确定的输入,一定会有确定的输出
- 函数在执行过程中,不会产生副作用
比如:
- 数组的slice方法不会修改原数组,而是生成一个新数组,所以slice就是一个纯函数
- splice方法会返回一个新数组,并且会修改原数组,所以splice方法不是一个纯函数
在React中组件被要求像是一个纯函数(为什么是像,因为还有class组件),Redux中的reducer要求必须是一个纯函数。
什么是副作用?
副作用是相对于主做用来说的,一个函数除了主作用,其他作用就是副作用。在执行一个函数式,除了返回函数值之外,还对做了其他的事情(副作用),比如修改了参数、外部变量等。常见的副作用:
- 数据请求ajax发送
- 手动修改dom
- localStorage操作 等
副作用经常会导致bug的出现!对于React组件来说,主做用就是根据数据(state/props)渲染UI,除此之外都是副作用。
Redux介绍
Redux 是 JavaScript 状态容器,提供可预测化的状态管理可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。Redux 经常和 React 一起使用,但是Redux和React并没有直接的关系,完全可以其它界面库中使用。 它体小精悍(只有2kB,包括依赖)。
为什么需要redux?
现在的前端应用已经变得越来越复杂,需要管理状态越来越多、越来越复杂;这些状态包括服务器返回的数据、用户操作产生的数据、缓存数据等,还有一些UI的状态,比如元素的选中样式,加载动画,分页状态;管理这些不断变化的状态是非常困难的,因为状态之间可能会相互依赖,状态变化时页面可能也会需要更新;当应用非常复杂时,这些状态在什么时候、因为什么、发生了怎样的变化是很难控制和追踪的;React本身的工作是根据state或者props帮助我们解决DOM的渲染过程,但是组件自己的state、组件通信时的props、context共享数据都是需要我们自己管理的。所以需要一个帮助我们管理状态的容器Redux,Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
Redux作者的建议
Redux的三大原则
单一数据源:
- 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
- Redux并没有强制不能创建多个store,但是多个store不利于维护
- 单一的数据源让整个应用的state变得方便修改、追踪和维护
State是只读的:
- 唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
- 这就确保了视图和网络请求都不能直接修改 state,只能通过action来表达自己想要如何修改state
- 因为所有的修改都被集中化处理,且严格按照顺序执行,因此不用担心 race condition (竞态)的出现
使用纯函数来执行修改:
- 为了描述 action 如何改变 state tree ,你需要编写 reducers。
- Reducer 只是一些纯函数,它将旧 state 和 action 联系在一起,返回新的 state
- 随着应用变大,可以把reducers拆成多个小的 reducer,分别独立地操作 state tree 的不同部分
- 所有的reducer都应该是纯函数,不能产生任何副作用
Redux核心概念-Store
Store 是把action和reducers联系到一起的对象。Store 有以下职责:
- 维护应用的 state;
- 提供
getState()
方法获取 state; - 提供
dispatch(action)
方法更新 state; - 通过
subscribe(listener)
注册监听器; - 通过
subscribe(listener)
返回的函数注销监听器。
Redux核心概念-action
Redux要求必须通过action来更新数据,actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state:
- 所有数据变化,必须使用dispatch(派发) action 来更新
- action是一个普通的JavaScript对象,用来描述这次更新的type和content
- 强制使用action的好处是可以清晰的知道数据到底发生了什么变化,所有的变化都是可追踪、可预测的
Redux核心概念-reducer
Reducers 描述了action如何修改 state:
Redux的基本使用
安装:npm install redux --save
const { createStore } = require("redux")
// 初始化的数据
const initialState = {
name: "jay",
age: 100
}
// 定义reducer函数: 纯函数
// 两个参数:
// 参数一: store中目前保存的state
// 参数二: 本次需要更新的action(dispatch传入的action)
// 返回值: 它的返回值会作为store之后存储的state
function reducer(state = initialState, action) {
switch (action.type) {
case "change_name":
return { ...state, name: action.name }
case "add_age":
return { ...state, age: state.age + action.age }
default:
// 默认需要返回原始的state
return state
}
}
// 多个reducer合并
// const reducer = combineReducers({
// user: userReducer,
// theme: themeReducer
// })
// 创建的store
const store = createStore(reducer)
// 获取state
// console.log('获取user state中的name:', store.getState().user.name)
console.log('获取state:', store.getState())
// 订阅state的变化
const unsubscribe = store.subscribe(() => {
console.log('订阅state的变化:', store.getState())
})
// 通过action修改state
const changeNameAction = { type: 'change_name', name: 'jay chou' }
store.dispatch(changeNameAction)
// 取消订阅
unsubscribe()
// 通过action修改state
const changeAgeAction = { type: 'change_name', age: 50 }
store.dispatch(changeAgeAction)
在React项目中使用Redux
Redux使用流程图
代码拆分
在实际的项目开发中,如果将所有的代码放到同一个文件中,那么在redux很复杂时,代码会变的难以维护。创建一个store文件夹,将代码按照 store(index.js)、reducer(reducer.js)、action(actionCreator.js)、actionTypes(actionTypes.js)拆分为一个个单独文件。
store/index.js
import { createStore } from "redux"
import reducer from "./reducer"
// 多个reducer合并
// const reducer = combineReducers({
// user: userReducer,
// theme: themeReducer
// })
// 创建的store
const store = createStore(reducer)
export default store
store/reducer.js
// 导入常量
import { CHANGE_NAME, CHANGE_AGE } from "./actionTypes"
// 初始化的数据
const initialState = {
name: "jay",
age: 44
}
function reducer(state = initialState, action) {
switch(action.type) {
case CHANGE_NAME:
return { ...state, name: action.name }
case CHANGE_AGE:
return { ...state, age: state.age + action.age }
default:
return state
}
}
export default reducer
store/actionCreators.js
// 导入常量
import { CHANGE_NAME, CHANGE_AGE } from "./actionTypes"
export const changeNameAction = (name) => ({
type: CHANGE_NAME,
name
})
export const changeAgeAction = (age) => ({
type: CHANGE_AGE,
age
})
store/actionTypes.js
export const CHANGE_NAME = "change_name"
export const CHANGE_AGE = "change_age"
在组件中使用
- 需要在componentDidMount中订阅store的变化,当数据变化时将最新的数据设置到组件的state
- 点击按钮时,调用store的dispatch派发修改数据的action
import React, { PureComponent } from 'react'
import store from './store'
import {changeNameAction} from './store/actionCreators'
export class App extends PureComponent {
constructor() {
super()
this.state = {
name: store.getState().name
}
}
componentDidMount() {
this.unsubscribe = store.subscribe(() => {
console.log('store更新了')
const name = store.getState().name
this.setState({ name })
})
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
const { name } = this.state
return (
<div>
<h2>用户名: {name}</h2>
<button onClick={() => store.dispatch(changeNameAction("Jay Chou"))}>修改name</button>
</div>
)
}
}
export default App
react-redux
介绍
React Redux是Redux的官方React UI绑定工具。它允许React组件从Redux存储读取数据,并将操作分派到存储以更新状态。 具有高效、灵活的特性。安装:npm install react-redux --save
Provider
redux-react提供了一个Provider组件,将其设置到所有组件的最外层,再将创建的store设置为Provider组件的store属性,可以使应用中的所有组件都能访问到Redux中的数据。
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from "react-redux"
import store from "./store"
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
// 使用 `<Provider>` 组件包裹 `<App>` 组件
// 并把 Redux store 作为 prop 传入
<Provider store={store}>
<App />
</Provider>
);
Connect
React Redux提供了一个连接函数,用于从Redux存储中读取值(并在存储更新时重新读取值)。connect函数接受两个参数,这两个参数都是可选的:
- mapStateToProps:每次store state更改时调用。它接收整个store state,将该组件需要的数据映射到组件的props。
- 没传该参数,组件不会在store发生变化时重新渲染
- mapDispatchToProps:此参数可以是函数,也可以是对象。
- 如果它是一个函数,它将在创建组件时被调用一次。它接收dispatch作为参数,并且应该返回一个对象,该对象包含使用dispatch来调度操作的函数。
- 如果它是一个充满action creators的对象,那么每个action creator 都会被映射到组件的props,在调用时自动dispatch 对应的 action。注意:建议使用“对象简写”形式
- 如果没有传该参数,可使用 props.dispatch 在组件中获取dispatch
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { changeNameAction, changeAgeAction } from './store/actionCreators'
export class App extends PureComponent {
render() {
console.log('render')
const { name, age, changeName, changeAge } = this.props
return (
<div>
<h2>用户名: {name}-age: {age}</h2>
<button onClick={() => changeName("Jay Chou")}>修改name</button>
<button onClick={() => changeAge(55)}>修改age</button>
</div>
)
}
}
const mapStateToProps = (state) => ({
name: state.name,
age: state.age,
})
// mapDispatchToProps是一个函数
// const mapDispatchToProps = (dispatch) => ({
// changeName(name) {
// dispatch(changeNameAction(name))
// },
// changeAge(age) {
// dispatch(changeAgeAction(age))
// }
// })
// mapDispatchToProps是一个对象
const mapDispatchToProps = {
changeName: changeNameAction,
changeAge: changeAgeAction
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
useSelector和useDispatch
在 React 函数组件中通过useSelector获取state,通过useDispatch获取dispatch方法。useSelector的作用从Store中获取state:
- 参数一:selector函数,selector 函数接收 Redux store 的 state 作为其参数,然后从 state 中取值并返回
- 参数二:可以通过比较来决定组件是否重新渲染
- **useSelector 使用严格的 === 来比较结果,因此只要 selector 函数返回的结果是新地址引用,组件就会重新渲染!**这意味着如果在 selector 中创建并返回新地址引用,那么每次 dispatch action 后组件都会被重新渲染,即使数据值确实没有改变。
- React-Redux 有一个 **shallowEqual **比较函数,我们可以使用它来检查数组 内部每一项 是否仍然相同
useDispatch调用后会返回dispatch函数,保存后可以在组件中直接使用;
import React, { memo } from 'react'
import { useSelector, useDispatch, shallowEqual } from "react-redux";
import { changeNameAction, changeAgeAction } from './store/actionCreators'
const App = memo(() => {
const {name, age} = useSelector(state => ({
name: state.name,
age: state.age
}), shallowEqual)
const dispatch = useDispatch()
const changeName = (name) => {
dispatch(changeNameAction(name))
}
const changeAge = (age) => {
dispatch(changeAgeAction(age))
}
return (
<div>
<h2>用户名: {name}-age: {age}</h2>
<button onClick={() => changeName("Jay Chou")}>修改name</button>
<button onClick={() => changeAge(55)}>修改age</button>
</div>
)
})
export default App
中间件Middleware
理解中间件
在前面的代码中都是一些同步操作,每当 dispatch action 时,state 会被立即更新。在真实的开发过程中,Redux中保存的数据可能来自服务器。在React中需要在class组件的componentDidMount生命周期、或者useEffect中发送网络请求获取数据,再将数据保存到Redux中。但是在Redux中进行异步操作标准的做法是使用 Redux Thunk 中间件。要引入 redux-thunk
这个专门的库才能使用。在 Express 或者 Koa 等服务端框中,middleware 是指可以被嵌入在框架接收请求到产生响应过程之中的代码。例如,Express 或者 Koa 的 middleware 可以完成添加 CORS headers、记录日志、内容压缩等工作。middleware 最优秀的特性就是可以被链式组合。可以在一个项目中使用多个独立的第三方 middleware。Redux 中间件被用于解决不同的问题,但其中的概念是类似的:
redux-thunk
- 默认情况 dispatch(action对象), action需要是一个JavaScript对象
- redux-thunk可以让dispatch(action函数),action可以是一个函数
- 该函数会被调用,并且会传给这个函数一个dispatch函数和getState函数
- dispatch函数:用于派发action
- getState函数:之后的一些操作可能需要原来的状态,可以获取之前的一些状态
- 安装:
npm install redux-thunk --save
- 使用:
- 使用applyMiddleware结合多个Middleware,返回一个enhancer函数
- 将enhancer作为第二个参数传入到createStore中
import { createStore, applyMiddleware } from "redux"
import thunk from "redux-thunk"
import reducer from "./reducer"
const enhancer = applyMiddleware(thunk)
const store = createStore(reducer, enhancer)
- 定义一个返回函数的action
export const fetchUserInfoAction = () => {
return function (dispatch, getState) {
// console.log("之前的state:", getState())
// 异步操作: 网络请求
fetch("http://xxx.xxx.xxx.xxx:8000/userInfo")
.then(res => res.json())
.then(res => {
const { name, age } = res.data
// 派发修改数据的action
dispatch(changeNameAction(name))
dispatch(changeAgeAction(age))
})
}
}
4.在组件中使用
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { fetchUserInfoAction } from './store/features/user'
export class App extends PureComponent {
componentDidMount() {
// 调用
this.props.fetchUserInfo()
}
render() {
console.log('render')
const { name, age } = this.props
return (
<div>
<h2>用户名: {name}-age: {age}</h2>
</div>
)
}
}
const mapStateToProps = (state) => ({
name: state.name,
age: state.age,
})
// const mapDispatchToProps = (dispatch) => ({
// fetchUserInfo() {
// dispatch(fetchUserInfoAction())
// }
// })
const mapDispatchToProps = {
fetchUserInfo: fetchUserInfoAction,
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
自定义中间件
function log(store) {
const next = store.dispatch
function logDispatch(action) {
console.log("当前派发的action:", action)
// 真正派发的代码: 使用之前的dispatch进行派发
next(action)
console.log("派发之后的结果:", store.getState())
}
// monkey patch: 猴补丁 => 篡改现有的代码, 对整体的执行逻辑进行修改
store.dispatch = logDispatch
}
function thunk(store) {
const next = store.dispatch
function dispatchThunk(action) {
if (typeof action === "function") {
action(store.dispatch, store.getState)
} else {
next(action)
}
}
store.dispatch = dispatchThunk
}
function applyMiddleware(store, ...fns) {
fns.forEach(fn => fn(store))
}
// 调用applyMiddleware
applyMiddleware(store, log, thunk)
Redux Tookit(RTK)
Redux Toolkit(简称RTK) 是 Redux 官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式。RTK可以帮助我们处理使用Redux过程中的重复性工作,简化Redux中的各种操作。安装:npm install @reduxjs/toolkit react-redux
createSlice
createSlice是一个全自动的创建reducer切片的方法。createSlice需要一个对象作为参数,对象中通过不同的属性来指定reducer的配置信息。const slice = createSlice(configuration object)
配置对象中的属性:
- name —— reducer的名字,会作为action中type属性的前缀,不要重复
- 在redux-devtool中会显示对应的name
- initialState —— state的初始值
- reducers —— reducer的具体方法,RTK会根据这些方法自动生成action对象,这些action对象会存储到切片对象actions属性中
- 对象类型,并且可以添加很多函数,每个函数相当于原来reducer中switch中的一个case语句
- 参数一:state
- 参数二:action对象
{type:'name/xxx', payload:...}
返回值是一个对象,里面包含自动生成的 reducer 和 actions(actionCreator组成的对象)。
import { createSlice } from "@reduxjs/toolkit"
const userSlice = createSlice({
name: "user",
initialState: {
name: jay,
age: 41,
},
reducers: {
changeName(state, { payload }) {
state.name = payload
},
changeAge(state, { payload }) {
state.age = payload
}
}
})
export const {changeName, changeAge} = userSlice.actions
export default userSlice.reducer
configureStore
configureStore用于创建store对象,参数是一个对象,在这个对象中可以通过不同的属性来对store进行设置:
- reducer:将createSlice返回的对象的reducer属性组成一个对象作为数据
- middleware:可选参数,传入中间件
- devTools:可选参数,是否配置devTools工具,默认为true
import { configureStore } from "@reduxjs/toolkit"
import userReducer from "./features/userSlice"
// import themeReducer from "./features/homeSlcie"
const store = configureStore({
reducer: {
user: userReducer,
// home: homeReducer
}
})
export default store
createAsyncThunk
之前需要使用redux-thunk中间件才可以在redux中进行异步操作。Redux Toolkit默认集成了thunk的功能:createAsyncThunk接收一个** action type 字符串和一个返回值为 promise 的函数**, 并生成一个 thunk 函数,这个 thunk 函数可以基于之前那个 promise ,dispatch 一组 type 为 pending/fulfilled/rejected 的 action:
- pending:action被发出,但是还没有最终的结果
- fulfilled:获取到最终的结果(有返回的结果)
- rejected:执行过程中有错误或者抛出了异常
也可以在createSlice的entraReducer中监听这些结果。
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
export const fetchUserInfoAction = createAsyncThunk(
"fetchUserInfo",
async (extraInfo, { dispatch, getState }) => {
// console.log(extraInfo, dispatch, getState)
const res = await fetch("http://xxx.xxx.xxx.xxx:8000/userInfo")
const resJson = await res.json()
const { name, age } = resJson.data
dispatch(changeName(name))
dispatch(changeAge(age))
// return resJson
}
)
const userSlice = createSlice({
name: "user",
initialState: {
name: jay,
age: 41,
},
reducers: {
changeName(state, { payload }) {
state.name = payload
},
changeAge(state, { payload }) {
state.age = payload
}
}
// extraReducers的第一种写法
// extraReducers: {
// [fetchUserInfoAction.pending](state, action) {
// console.log("fetchUserInfoAction pending")
// },
// [fetchUserInfoAction.fulfilled](state, { payload }) {
// console.log("fetchUserInfoAction fulfilled")
// // const { name, age } = payload.data
// // state.name = name
// // state.age = age
// },
// [fetchUserInfoAction.rejected](state, action) {
// console.log("fetchUserInfoAction rejected")
// }
// },
// extraReducers的第二种写法
// extraReducers: (builder) => {
// builder.addCase(fetchUserInfoAction.pending, (state, action) => {
// console.log("fetchUserInfoAction pending")
// }).addCase(fetchUserInfoAction.fulfilled, (state, { payload }) => {
// // const { name, age } = payload.data
// // state.name = name
// // state.age = age
// })
// }
})
export const { changeName, changeAge } = userSlice.actions
export default userSlice.reducer
在组件中使用
import React, { PureComponent } from 'react'
import { connect } from "react-redux"
import { fetchUserInfoAction } from './store/features/userSlice'
export class Home extends PureComponent {
componentDidMount() {
this.props.fetchHomeMultidata()
}
render() {
console.log('render')
const { name, age } = this.props
return (
<div>
<h2>用户名: {name}-age: {age}</h2>
</div>
)
}
}
const mapStateToProps = (state) => ({
name: state.user.name,
age: state.user.age,
})
const mapDispatchToProps = (dispatch) => ({
fetchUserInfo() {
dispatch(fetchUserInfoAction())
}
})
export default connect(mapStateToProps, mapDispatchToProps)(App)
数据不可变性
在React中开发中,总会强调数据的不可变性
- 无论是类组件中的state,还是redux中管理的state
- 事实上整个JavaScript编码过程中,数据的不可变性都是非常重要的’
我们经常会通过浅拷贝来完成某些操作,但是浅拷贝事实上也是存在问题的:
- 比如:过大的对象,进行浅拷贝也会造成性能的浪费
- 比如:浅拷贝后的对象,在深层改变时,依然会对之前的对象产生影响
事实上Redux Toolkit底层使用了immerjs的一个库来保证数据的不可变性为了节约内存,又出现了一个新的算法:Persistent Data Structure(持久化数据结构或一致性数据结构)
Redux Tookit Query(RTKQ)
RTKQ是一种功能强大的数据获取和缓存工具,它已经集成在了RTK中,默认使用简单封装过得fetch发送请求。它旨在简化在web应用程序中加载数据的常见情况,无需自己手工编写数据获取和缓存逻辑。Web应用中加载数据时需要处理的问题:
- 根据不同的加载状态显示不同UI组件
- 减少对相同数据重复发送请求
- 使用乐观更新,提升用户体验
- 在用户与UI交互时,管理缓存的生命周期
这些问题RTKQ都可以帮助我们处理。首先,可以直接通过RTKQ向服务器发送请求加载数据,并且RTKQ会自动对数据进行缓存,避免重复发送不必要的请求。其次,RTKQ在发送请求时会根据请求不同的状态返回不同的值,可以通过这些值来监视请求发送的过程并随时中止。
创建一个API Slice
createApi需要一个对象作为参数,常用属性如下,更多属性可查看官网:
- reducerPath:Api的唯一标识,主要用来创建store时指定action的type属性,如果不指定默认为api
- baseQuery:用来设置发送请求的工具,就是用什么发请求(点击),RTKQ提供了fetchBaseQuery作为查询工具,它对fetch进行了简单的封装
- fetchBaseQuery:简单封装过的fetch调用后会返回一个封装后的工具函数。需要一个配置对象作为参数,baseUrl表示Api请求的基本路径,指定后请求将会以该路径为基本路径。更多属性查看官网。
- tagTypes: 字符串标记类型名称的数组。指定标记类型是可选的,但您应该定义它们,以便它们可以用于缓存和无效。定义标记类型时,您将能够为它们提供providesTag,并在配置终结点时使用invalidatesTag使其无效。
- endpoints:endpoints是一个回调函数。回调函数接收一个build对象,使用build对象对点进行映射。回调函数的返回值是一个对象,Api对象中的所有端点都要在该对象中进行配置。
- 返回值对象的属性名就是要实现的功能名,比如获取用户信息getUserInfo
- 查询方法:build.query() 参数是一个对象,常用属性如下
- query():函数,接收参数,需要返回一个string(请求子路径)或者object(请求的配置对象包含url、method、headers、body、params等)
- transformResponse(baseQueryReturnValue, meta, arg):用来转换相应数据的格式
- keepUnusedDataFor:数据缓存的时间,单位秒
- providesTags:确定哪个“标记”附加到查询返回的缓存数据。应为标记类型字符串的数组、带id的标记类型对象的数组,或返回此类数组的函数。
- 增删改:build.mutation()
- invalidatesTags:确定应重新提取或从缓存中删除哪些缓存数据。应该和providesTag相同。
- 钩子函数名字为useXxxQuery或useXxxMutation,中间的Xxx就是方法名
/* React-specific entry point that automatically generates
hooks corresponding to the defined endpoints */
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
// import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";
const userApi = createApi({
reducerPath: 'userApi',
// 指定查询的基础信息,发送请求使用的工具
baseQuery: fetchBaseQuery({
baseUrl: 'http://localhost:8000'
}),
// endpoints 用来指定Api中的各种功能,是一个方法,需要一个对象作为返回值
endpoints(build) {
// build是请求的构建器,通过build来设置请求的相关信息
return {
getUserInfo: build.query({
query() {
return '/home/multidata'
}
})
}
}
})
// Api对象创建后,对象中会根据各种方法自动的生成对应的钩子函数
// 通过这些钩子函数,可以来向服务器发送请求
// 钩子函数的命名规则 getStudents --> useGetStudentsQuery
export const {useGetUserInfoQuery} = userApi
export default userApi
配置到Store中
- 添加createApi生成的reducer到store
- 添加自动生成的中间件,中间件用来实现缓存、轮询等
import { configureStore } from "@reduxjs/toolkit"
import userReducer from "./features/userSlice"
// import themeReducer from "./features/homeSlcie"
import userApi from "./api/userApi"
const store = configureStore({
reducer: {
user: userReducer,
// home: homeReducer
[userApi.reducerPath]: userApi.reducer
},
// 添加api中间件
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(userApi.middleware),
})
export default store
在函数式组件中使用query hooks
hook返回的对象中包含了以下属性:
- data:最新返回的数据
- currentData:当前的数据
- error:错误信息
- isUninitialized:如果为true则表示查询还没开始
- isLoading:为true时,表示请求正在第一次加载
- isFetching:为true时,表示请求正在加载
- isSuccess:为true时,表示请求发送成功
- isError:为true时,表示请求有错误
- refetch:函数,用来重新加载数据
useXxxQuery的第一个参数是传入的数据;useXxxQuery可以接收一个对象作为第二个参数,通过该对象可以对请求进行配置:
- selectFromResult:指定返回的结果,对返回的结果进行筛选
- pollingInterval:设置轮询的间隔,单位毫秒 如果为0则表示不轮询
- skip:是否跳过当前请求,默认false
- refetchOnMountOrArgChange:是否每次都重新加载数据 false正常使用缓存,true每次都重载数据,数字表示数据缓存的时间(秒)
- refetchOnFocus:是否在重新获取焦点时重载数据
- refetchOnReconnect:是否在重新连接后重载数据
import React, { memo } from 'react'
import { useGetUserInfoQuery } from '../store/api/homeApi'
const Home = memo(() => {
// 调用api中的钩子获取数据
// 返回值是一个对象,请求过程中相关数据都在该对象中
const {data, isSuccess, isLoading} = useGetUserInfoQuery();
const {name, age} = data.data
return (
<div>
{isLoading && <h2>加载中....</h2>}
{isSuccess && <h2>成功!</h2>}
<h2>用户名: {name}-age: {age}</h2>
</div>
)
})
export default Home
转载自:https://juejin.cn/post/7269006875843821625