提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
RTK Query injectEndpoints
系列文章:
RTK Qurey+TypeScript基本使用(一):查询与添加数据
RTK Qurey+TypeScript基本使用(二):缓存刷新
RTK Qurey+TypeScript基本使用(三):修改本地缓存
前言
大型应用程序通常会将功能代码拆分到单独的包中,然后在首次使用该功能时按需延迟加载它们。
RTK Query 支持使用 apiSlice.injectEndpoints()
拆分请求接口。
// dataType/IPostState.tsx
import IReaction from "./IReaction";
interface IPostState {
id: string;
title: string;
content: string;
user: string;
date: string;
}
export default IPostState;
// dataType/IUserState.tsx
interface IUserState {
id: string;
name: string
}
export default IUserState
// redux/apiSlice.tsx
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import IPostState from '../dataType/IPostState'
export const apiSlice = createApi({
reducerPath: 'baseapi',
baseQuery: fetchBaseQuery({ baseUrl: 'http://127.0.0.1:8780/fakeApi' }),
endpoints: builder => ({
// 查询数据
getPosts: builder.query<IPostState[], void>({
query: () => '/posts',
providesTags: ['Post']
})
})
})
export const { useGetPostsQuery } = apiSlice
// redux/store.tsx
import { configureStore } from '@reduxjs/toolkit'
import { apiSlice } from './apiSlice'
const store = configureStore({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer
},
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(apiSlice.middleware)
})
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;
// index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<Provider store={store}>
<App />
</Provider>
);
injectEndpoints的基本使用
我们使用 injectEndpoints()
对请求接口进行拆分
// redux/usersSlice.tsx
import IUserState from '../dataType/IUserState'
import { RootState } from "./store"
//注入接口
export const extendedApiSlice = apiSlice.injectEndpoints({
endpoints: builder => ({
getUsers: builder.query<IUserState[], void>({
query: () => '/users',
})
})
})
export const { useGetUsersQuery } = extendedApiSlice
在其它组件调用 useGetUsersQuery
就可以获取对应的值
transformResponse的基本使用
假如现在我需要对返回的数据进行一定的处理
// redux/usersSlice.tsx
import { createEntityAdapter, EntityState } from '@reduxjs/toolkit'
import { apiSlice } from "./apiSlice"
import IUserState from '../dataType/IUserState'
// 范式化数据
const usersAdapter = createEntityAdapter<IUserState>()
const initialState = usersAdapter.getInitialState([])
//注入接口
export const extendedApiSlice = apiSlice.injectEndpoints({
endpoints: builder => ({
getUsers: builder.query<EntityState<IUserState>, void>({
query: () => '/users',
//该处理程序可以在缓存之前,提取或修改从服务器接收到的数据
transformResponse: (response: IUserState[]) => {
return usersAdapter.setAll(initialState, response)
}
})
})
})
export const { useGetUsersQuery } = extendedApiSlice
这个时候我们再去调用 useGetUsersQuery
获取到的数据就不是从服务端获取的到的源数据了,而是在 transformResponse
中经过处理之后的数据
使用useSelector()来获取RTK query的数据
假如一份数据在程序中很多地方都要反复用到,而每个地方都调用 useGetUsersQuery
之类的方法来获取数据,显示的十分麻烦,而我们希望像redux那种使用 useSelector()
来获取数据
我们可以这样来实现
// redux/usersSlice.tsx
import { createEntityAdapter, createSelector, EntityState } from '@reduxjs/toolkit'
import { apiSlice } from "./apiSlice"
import IUserState from '../dataType/IUserState'
import { RootState } from "./store"
// 范式化数据
const usersAdapter = createEntityAdapter<IUserState>()
const initialState = usersAdapter.getInitialState([])
//注入接口
export const extendedApiSlice = apiSlice.injectEndpoints({
endpoints: builder => ({
getUsers: builder.query<EntityState<IUserState>, void>({
query: () => '/users',
//该处理程序可以在缓存之前提取或修改从服务器接收到的数据
transformResponse: (response: IUserState[]) => {
return usersAdapter.setAll(initialState, response)
}
})
})
})
export const { useGetUsersQuery } = extendedApiSlice
// 获取请求的selector,就返回的查询请求
const selectUsersResult = extendedApiSlice.endpoints.getUsers.select()
//查出返回的查询请求中的数据,data为EntityState<IUserState>类型|undefined
const selectUsersData = createSelector(
selectUsersResult,
(usersResult) => usersResult.data
)
// 有结果出结果,没结果返回初始化的值
// 注意:?? initialState这个一定写啊,因为在请求查询没有完成之前,state中getUsers这个分支是没有值的
// 而这个时候恰好代码调用了,会导致报错,所有我们需要给它弄个默认值之类的
const selectUsers = (state: RootState) => selectUsersData(state) ?? initialState
//查询所有用户,查询特定id的用户
export const { selectAll: selectAllUsers, selectById: selectUserById } = usersAdapter.getSelectors(selectUsers)
在index.tsx
中手动调用getUsers
,初始化数据
// index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';
import { extendedApiSlice } from './redux/usersSlice';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
//手动调用,初始化数据
store.dispatch(extendedApiSlice.endpoints.getUsers.initiate())
root.render(
<Provider store={store}>
<App />
</Provider>
);
之后我们就可以其它组件调用 useSelector()
来获取数据了
// App.tsx
import React from 'react'
import { useSelector } from 'react-redux'
import { RootState } from './redux/store'
import { selectAllUsers, selectUserById } from './redux/usersSlice'
function App() {
//查询所有数据
let users = useSelector(selectAllUsers)
console.log(users)
//查询特定id的数据
let user = useSelector((state: RootState) => selectUserById(state, '0'))
console.log(user)
return (
<div>
</div>
)
}
export default App