react+ts实战之 @reduxjs/toolkit

本文介绍Redux结合@reduxjs/toolkit的高效使用方式,包括简化工作流、异步处理及store持久化策略,对比传统Redux与现代工具包的区别。
前言

Store的宗旨是为了复杂组件数据共享而设计,因此使用场景在设计层尽可能减少,否则极大加剧了项目的复杂度,正如官方所说的那样在你考虑用和不用的时候,那就是不用。

react的社区是足够大的,他不像vue那样cli官方给你构建一套完整的全家桶,如vue+vue-router+vuex,它更多的是像买车一样,给你提供选配的模式,出了本身的基础配置之外,你是要定制的皮制座椅(flux)还是星空顶(redux)…需要什么样的插件,自己就去市场选配什么插件,我们今天来讲一下主流的redux

一、redux的工作流

View调用store.dispatch发起Action->store接受Action(action传入reducer函数,reducer函数返回一个新的state)->通知store.subscribe订阅的重新渲染函数
在这里插入图片描述

二、redux曾经的使用案例

在前几年我们使用的就是这样,没错,非常完整规范的redux操作流程。reduceractionstore清晰明了,就是有一点,em…老太婆裹脚—又臭又长。所以在vue2发布以后,我们团队果断选择了vue直到现在,我个人目前也更为擅长vue的各个版本。
store.js

import {createStore} from 'redux'
import Reducer from './reducer'
const Store = createStore(Reducer)

export default Store; 

Reducer.js

const Reducer = (state,action)=>{
	if(typeof state === 'undefined'){
		return []
	}
	switch (action.type){
		case 'CON_TODO':
		return [...state,action.text]
		break;
		case 'TONN_DEL':
		state.splice(action.text,1)
		return state
		break;
		default:
		return state
			break;
	}
}


export default Reducer;

action.js

var Action = (text)=>{
	return{
		type:"CON_TODO",
		text:text
	}
}
export default Action; 

实际使用

import React from 'react'
import ReactDOM from 'react-dom'
import {createStore} from 'redux'
import Action from './Store/action.js'
import Store from './Store/store.js'
class App extends React.Component{
	constructor(props){
		super(props)
		this.shuju = this.shuju.bind(this)
		this.state={
			arr:Store.getState()
		}
	}
	del(a){
		Store.dispatch(Action1(a))
	}
	componentDidMount(){
		Store.subscribe(this.shuju)
	}
}
三、@reduxjs/toolkit 基于redux的工具库
3.1 基础案例

@reduxjs/toolkit这个是我们react实战项目中的一个重点知识,能帮我们解决redux多余的代码,而且让我们的代码更加清晰明了。以下是一个简单的案例,我们引入了一个关于counter的reducer切片

// store/index.ts
import { configureStore } from '@reduxjs/toolkit'
import counterSlice from './counterSlice'
export const store = configureStore({
  reducer: {
    counter: 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

再来看一下具体的切片内容:

// store/counterSlice.ts	
import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit'
export interface CounterState {
  isLogin: boolean
  value: number
  featchVal: number
}

const initialState: CounterState = {
  isLogin: false,
  value: 0,
  featchVal: 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
3.2 @reduxjs/toolkit+store持久化

我们如果想加上store的持久化呢,也就是说对store的内容进行本地存储,这里使用的是redux-persist,此时注意了,@reduxjs/toolkit仍然支持,也就是说项目基本不需要引入redux的任何依赖,它本身就是对redux的功能的封装与补充,而且支持自定义的中间件middleware,再来看一下:

// store/index.ts
import { configureStore, combineReducers } from '@reduxjs/toolkit'
import { persistStore,persistReducer} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import counterReducer from './counterSlice'
// ...

export const rootReducer = combineReducers({
  counter: counterReducer
})
const persistConfig = {
  key: 'root',
  storage ,
  blacklist:[]
}
const myPersistReducer = persistReducer(persistConfig, rootReducer)
export const store = configureStore({
  reducer: myPersistReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false,
    })
})

export const persistor = persistStore(store)
3.3 处理异步

通常情况下store是没有处理异步的能力的,所以我们更多的是通过市场上提供的一些处理异步的解决方案,如redux-thunk
但是我们这里不需要,因为仍然有处理异步的方案,我们接着在counterSlice.ts中进行拓展

import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit'

export interface CounterState {
  isLogin: boolean
  value: number
  featchVal: number
}

const initialState: CounterState = {
  isLogin: false,
  value: 0,
  featchVal: 0
}

export const fetchSettimeout = createAsyncThunk(
  'counter/fetchSettimeout', (id: number)=>{
    return new Promise<number>((resolve) => {
      setTimeout(()=>{
       resolve(id)
      },3000)
    })
  }
)

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
    }
  },
  extraReducers: (builder) => {
    builder.addCase(fetchSettimeout.fulfilled, (state, action) => {
      console.log(state, action)
      state.featchVal = action.payload
    })
  }
})
// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer

我们用 fetchSettimeout方法封装了一个setTimeout来模拟了异步,这里只是一种写法,更多的查看点击前往官网

3.4 Hook封装

项目中我们希望借助react-redux来实现store的管理,但是不能直接去使用其中的一些api,可能会导致ts错误,因此我们单独拆出来做了一层Hook封装并进行类型声明

// src/hooks
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import { store } from '@/store'


export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
3.5 实际使用案例
root.render(
  <React.StrictMode>
    <Provider store={ store }>
      <App />
     </Provider>
   </React.StrictMode>
)
import { RootState,useAppDispatch,useAppSelector } from '@/hooks/store'
import { increment, decrement, fetchSettimeout } from '@/store/counterSlice'
const Home: React.FC = () => {
  const dispatch = useAppDispatch()
  const {featchVal, value} = useAppSelector((state: RootState) => state.counter)
  return (
    <div className="home">
       数据变化:{featchVal}
       数据:{value}
      <Button type="primary" onClick={() => dispatch(increment())}>store点击++</Button>
      <Button type="primary" onClick={() => dispatch(fetchSettimeout(21313213))}>点击请求</Button>
    </div>
}
export default Home
总结与对比

不知道大家看出来什么没有,有没有跟vuex的语法特别接近了呢,正所谓所谓合久必分,分久必合。任何一个框架除了性能作为首选推荐之外,其次就要考虑哪种语法更贴合开发的使用习惯,更简单明了。不知道当前的你是不是还在使用最原始的redux+local来管理数据呢???

vuex@reduxjs/toolkit
namename
stateinitialState
mutationscreateSlice-reducers
actionscreateAsyncThunk+extraReducers
modulesconfigureStore-reducer
<think>好的,用户想了解@reduxjs/toolkit/query/react是什么以及如何使用。首先,我需要回忆一下Redux Toolkit的相关知识。记得Redux Toolkit(RTK)是Redux官方推荐的简化库,而RTK Query是其中的数据获取和缓存解决方案,专门处理API交互。 用户提到的@reduxjs/toolkit/query/react应该是RTK Query针对React的绑定库。需要确认它和react-redux的区别,引用中提到的区别是redux是架构模式,而RTK是工具包,包含RTK Query。所以RTK Query用于管理服务器状态,而react-redux用于连接React组件和Redux store。 接下来要解释RTK Query的作用,比如自动生成API slice、缓存管理、数据预取等。然后步骤应该包括安装、创建API服务、配置store、在组件中使用生成的hooks。 需要注意用户可能需要具体的代码示例,比如如何定义endpoints,如何注入middleware,以及如何使用useQuery和useMutation。还要提到优势,比如减少样板代码,自动缓存,TypeScript支持等。 可能用户在使用中会遇到问题,比如如何配置baseUrl,如何处理错误,如何触发重新获取数据。需要确保步骤清晰,代码正确,并引用之前的参考资料,比如引用[1]提到的创建项目模板和安装方法,以及引用[2]中关于RTK和react-redux的区别。 最后生成相关问题,覆盖RTK Query的其他功能、缓存策略、与传统Redux的区别,以及错误处理等。这样用户可以有进一步的学习方向。</think>### @reduxjs/toolkit/query/react 使用指南 #### 一、概念理解 `@reduxjs/toolkit/query/react` 是 Redux Toolkit(RTK)的扩展模块,专门用于简化 **API 数据交互** 和 **状态管理**。它通过自动生成 API 请求逻辑、缓存管理和状态更新,显著减少手动编写 Redux 代码的工作量[^1]。 #### 二、核心功能 1. **自动生成 API Slice**:通过定义 API endpoints 自动生成 Redux slice 2. **缓存策略**:支持数据自动缓存、失效和更新 3. **Hooks 支持**:为 React 组件提供 `useQuery`、`useMutation` 等 hooks 4. **预加载与乐观更新**:支持数据预加载和乐观 UI 更新 #### 三、使用步骤 ##### 1. 安装依赖 ```bash npm install @reduxjs/toolkit react-redux @reduxjs/toolkit/query/react ``` ##### 2. 创建 API 服务 ```typescript // api/userApi.ts import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' export const userApi = createApi({ reducerPath: 'userApi', baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: (builder) => ({ getUsers: builder.query<User[], void>({ query: () => '/users', }), addUser: builder.mutation<void, Partial<User>>({ query: (body) => ({ url: '/users', method: 'POST', body, }), }), }), }) export const { useGetUsersQuery, useAddUserMutation } = userApi ``` ##### 3. 配置 Redux Store ```typescript // store.ts import { configureStore } from '@reduxjs/toolkit' import { userApi } from './api/userApi' export const store = configureStore({ reducer: { [userApi.reducerPath]: userApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(userApi.middleware), }) ``` ##### 4. 在组件中使用 ```tsx // UserList.tsx import { useGetUsersQuery } from './api/userApi' const UserList = () => { const { data, error, isLoading } = useGetUsersQuery() if (isLoading) return <div>Loading...</div> if (error) return <div>Error!</div> return ( <ul> {data?.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> ) } ``` #### 四、主要优势 1. **代码简化**:相比传统 Redux 减少约 80% 的样板代码 2. **自动缓存**:默认 60 秒缓存时间(可配置) 3. **TS 支持**:完整的 TypeScript 类型推断 4. **集成 DevTools**:通过 Redux DevTools 调试 API 状态 #### 五、典型应用场景 1. 需要频繁调用 REST/GraphQL API 的 SPA 应用 2. 需要实时数据更新的 dashboard 类应用 3. 需要处理复杂缓存逻辑的电商平台
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

槿畔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值