RTK + RTK Query模式管理前端数据流程实践

611 阅读4分钟

鉴于我找不到一个合适的引子来引出今天的focus,于是选择直奔主题。 本篇内容我主要介绍RTK + RTK Query模式管理基于React开发前端应用的数据管理理论与实践。

理论概念

RTK是什么?

Redux Toolkit, 简称RTK,redux的工具集,主要目的是react使用redux更加便捷,其底层逻辑依然是redux的概念,Toolkit提供了一些固定的模式,我们只需要根据其样板文件就可以将redux无缝集成到react的项目中,其目的就是让开发者focus项目的业务逻辑即可。

RTK Query是什么?为什么有RTK Query?

RTK Query是RTK的一个插件(addon),不需要单独安装,直接从RTK的包中就可以导出。用过react-query或者useRequest的会更好接受这个,这个RTK Query跟这两个事物还是蛮有重合的。说到这就不得不说下自己的一点小感受,不知道从什么时候开始,前端开发者开始把每个请求的状态都抽象出来了,当我还沉浸在axios如此好用的喜悦中之后,猛然发现社区里有useRequest这样的hook,然后又继而到react-query,RTK Query这些事物。嗯,就是这样,觉得不学就落后了应该学但是实际好像不用这些也可以写项目,这种纠结蛮难受,最终半推半掩的接受这些新事物,虽然现在已不算什么新事物了。 最终选择RTK Query,纯粹是因为代码洁癖,因为不想引入更多的东西,想用一套链路完事,所以RTK Query平替了axios的使用。

总的来说,RTK Query承接了API层的数据问题,加上RTK提供的Redux的前端数据管理方式,基本实现了一个完整的数据链路,是一个完备的数据管理方案。

实践操作

这部分主要介绍一下,react项目中使用RTK+RTK Query管理数据的具体实施步骤:

1、依赖安装

npm i redux react-redux @reduxjs/toolkit

2、创建数据仓库
import {configureStore} from '@reduxjs/toolkit'

// 导出数据仓库store
export const store = configureStore({  
    reducer: {},  
})

// Infer the `RootState` and `AppDispatch` types from the store itself  
export type RootState = ReturnType<typeof store.getState>  
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}  
export type AppDispatch = typeof store.dispatch
3、将store集成到react application中
// 导入步骤二创建的store
import {store} from './store.ts
import {Provider} from 'react-redux'

ReactDOM.render(
    <Provider store={store}>  
        <App />  
    </Provider>,  
    document.getElementById('root')  
)
4、根据slice样板文件创建带有业务数据的state slice
// 这个文件来自官网(https://redux-toolkit.js.org/tutorials/quick-start)提供的一个样板文件
import { createSlice } from '@reduxjs/toolkit'  
import type { PayloadAction } from '@reduxjs/toolkit'  

const initialState: CounterState = {  
    value: 0,  
}  
  
export const counterSlice = createSlice({  
    name: 'counter',  
    initialState,  
    reducers: {  
        increment: (state) => {  
            state.value += 1  
        },  
        decrement: (state) => {  
            state.value -= 1  
        },  
        incrementByAmount: (state, action: PayloadAction<number>) => {  
            state.value += action.payload  
        },  
    },  
})  
  
// Action creators are generated for each case reducer function  
export const { increment, decrement, incrementByAmount } = counterSlice.actions  
  
export default counterSlice.reducer
5、将步骤4中的slice集成到store中
import {configureStore} from '@reduxjs/toolkit'
// 步骤4中导出的slice
import counterReducer from './counterSlice'

// 导出数据仓库store
export const store = configureStore({  
    reducer: {
        counter: counterReducer // 将counterSlice放到这里
    },  
})

// Infer the `RootState` and `AppDispatch` types from the store itself  
export type RootState = ReturnType<typeof store.getState>  
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}  
export type AppDispatch = typeof store.dispatch
6、RTK Query创建API service
// 直接从toolkit中导入即可 
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'  
  
// Define a service using a base URL and expected endpoints  
export const userApi = createApi({  
    reducerPath: 'userApi',  
    baseQuery: fetchBaseQuery({ baseUrl: 'https://domain:port/api/' }),  
    endpoints: (builder) => ({  
        getUserInfo: builder.query<any, string>({  
            query: (name) => `getUserInfo/${name}`,  
        }),  
    }),  
})  
  
// 导出自动生成的hooks使用
export const { useGetUserInfoQuery } = userApi
7、将API service也理解为一种state slice集成到store中
import {configureStore} from '@reduxjs/toolkit'
// 步骤4中导出的slice
import counterReducer from './counterSlice'
// 步骤6中导出的api slice
import {userApi} from './userApi'

// 导出数据仓库store
export const store = configureStore({  
    reducer: {
        counter: counterReducer, // 将counterSlice放到这里
        [userApi.reducerPath]: userApi.reducer
    },  
    middleware: (getDefaultMiddleware) => {
        getDefaultMiddleware().concat(userApi.middleware) // 可以当作样板代码
    }
})

// Infer the `RootState` and `AppDispatch` types from the store itself  
export type RootState = ReturnType<typeof store.getState>  
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}  
export type AppDispatch = typeof store.dispatch
8、react component中使用store中的数据和action
// 导入userApi中导出自动生成的query hook
import {useGetUserInfoQuery} from './userApi'

export default function App() {
    // hook调用返回data,error,isLoading,因为是hook,数据变更后会引起组件重新执行,完成业务逻辑
    const {data, error, isLoading} = useGetUserInfoQuery('name')
    
    // 这里放业务逻辑展示即可
    return (
        <div></div>
    )
}

小结

至此,一个完整的RTK+RTK Query管理前端数据的方案已经完毕。上述代码大部分截取其官网展示的示例code,只是将RTK和RTK Query的示例代码拼接在一起形成一个完整的实践操作。目前该套方案已经在多个项目中使用,基本覆盖了业务需求场景,总体感受这套方案还算清晰优雅。