当前位置: 首页 > article >正文

React--》Redux Toolkit的使用讲解

目录

Redux Toolkit

redux toolkit的基本使用

RTK代码模块化

RTK QUERY的使用

useQuery参数


Redux Toolkit

Redux Toolkit是Redux的工具包,简称RTK,可以帮助我们处理使用Redux过程中的重复性工作,简化Redux中的各种操作,当然博主也不可能将RTK讲解的面面俱到,看完本篇文章后还是推荐大家多多看一下 官方文档 ,无论是RTK还是Redux,在React中使用 react-redux 都是必不可少的,所以使用RTK依然需要安装两个包,如下:

npm install react-redux @reduxjs/toolkit

redux toolkit的基本使用

官方已经给出我们使用redux toolkit的基本示例了,如下图所示,在这里我结合官方给出的示例简单的说明并讲解一下函数的使用。

根据官方给出的基础案例,在src文件夹下新建文件夹store,然后新建index.jsx文件,并写出如下代码:

// 使用RTK创建store, createSlice 创建reducer的切片
import { configureStore, createSlice } from "@reduxjs/toolkit";
const stuSlice = createSlice({ // 需要一个配置对象作为参数,通过对象的不同属性来指定它的配置
  name:'stu', // 用来自动生成 action 中的 type
  initialState:{ // state的初始值
    name:"张三",
    age:18,
    gender:"男",
    address:"北京"
  },
  // 指定state的各种操作,直接在对象中添加方法
  reducers:{
    setName: state => { // state是一个代理对象,可直接修改
      state.name = "李四"
    },
    setAge: state => {
      state.age = 28
    }
  }
})
// 切片对象会自动的帮助我们生成action
export const { setName,setAge } = stuSlice.actions
// 创建store,用来创建store对象,需要一个配置对象作为参数
const store = configureStore({
  reducer:{
    student:stuSlice.reducer
  }
})
export default store

要想在全局使用store文件中定义的数据和方法,需要在入口文件main.js文件中进行如下操作:

import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { Provider } from 'react-redux'
import store from './store'

ReactDOM.createRoot(document.getElementById('root')).render(
    <Provider store={store}>
        <App />
    </Provider>
)

接下里通过调用redux相关api来获取数据和方法。

import { useSelector,useDispatch } from "react-redux"
import { setName,setAge } from "./store"
const App = () => {
  // useSelector() 用来加载state中的数据
  const student = useSelector(state => state.student)
  // 通过useDispatch() 来获取派发器对象
  const dispatch = useDispatch()
  const changeName = () =>{ 
    dispatch(setName())
  }
  const changeAge = () =>{ 
    dispatch(setAge())    
  }
  return (
    <div>
      <p>{student.name}--{student.age}--{student.gender}--{student.address}</p>
      <button onClick={changeName}>修改名字</button>
      <button onClick={changeAge}>修改年龄</button>
    </div>
  )
}
export default App

如果想通过传参的方式进行修改数据的话,可以采用以下这种方式:

RTK代码模块化

因为state的数据可能不止一种,将每一种数据都存放在store的一个文件中就会显得代码特别的臃肿,后期难以维护,为了便于今后的管理,可以对RTK代码进行模块化划分,也就是说,每一个数据都有单独的文件,最后所有的文件都整合到store文件夹下的index文件中,如下:

将我设置好的两个store数据单独抽离出去:

import { createSlice } from "@reduxjs/toolkit";
// 创建学生切片
const stuSlice = createSlice({ // 需要一个配置对象作为参数,通过对象的不同属性来指定它的配置
  name:'stu', // 用来自动生成 action 中的 type
  initialState:{ // state的初始值
    name:"张三",
    age:18,
    gender:"男",
    address:"北京"
  },
  // 指定state的各种操作,直接在对象中添加方法
  reducers:{
    setName: (state,action) => { // state是一个代理对象,可直接修改
      state.name = action.payload
    },
    setAge: (state,action) => {
      state.age = action.payload
    }
  }
})
// 切片对象会自动的帮助我们生成action
export const { setName,setAge } = stuSlice.actions
export const { reducer:stuReducer } = stuSlice
import { createSlice } from "@reduxjs/toolkit";
// 创建学校切片
const schoolSlice = createSlice({
  name:"school",
  initialState:{
    name:'北京大学',
    address:'北京市',
  },
  reducers:{
    setName: (state,action) => {
      state.name = action.payload
    },
    setAddress: (state,action) => {
      state.address = action.payload
    }
  }
})
export const { setName,setAddress } = schoolSlice.actions
export const { reducer:schoolReducers  } = schoolSlice

将抽离出去的数据都存放在store文件夹下的index.jsx文件中,如下:

// 使用RTK创建store,用于管理所有数据的文件
import { configureStore } from "@reduxjs/toolkit"; 
import { stuReducer } from "./student";
import { schoolReducers } from "./school";

// 创建store,用来创建store对象,需要一个配置对象作为参数
const store = configureStore({
  reducer:{
    student:stuReducer,
    school:schoolReducers
  }
})
export default store

在相关组件中调用该store中的数据:

import { useSelector,useDispatch } from "react-redux"
import { setName,setAge } from "./store/student"
import { setAddress,setName as setSchoolName } from "./store/school"

const App = () => {
  // useSelector() 用来加载state中的数据
  const { student,school } = useSelector(state => state)
  // 通过useDispatch() 来获取派发器对象
  const dispatch = useDispatch()
  const changeName = () =>{ 
    dispatch(setName("王五"))
  }
  const changeAge = () =>{ 
    dispatch(setAge(30))    
  }
  const changeSchoolName = () =>{ 
    dispatch(setSchoolName("五道口职业技术学院"))
  }
  const changeSchoolAddress = () =>{ 
    dispatch(setAddress("海淀区"))
  }
  return (
    <div>
      <h2>个人信息:</h2>
      <p>{student.name}--{student.age}--{student.gender}--{student.address}</p>
      <button onClick={changeName}>修改个人名字</button>
      <button onClick={changeAge}>修改个人年龄</button>
      <h2>学校信息:</h2>
      <p>{school.name}--{school.address}</p>
      <button onClick={changeSchoolName}>修改学校名字</button>
      <button onClick={changeSchoolAddress}>修改学校地址</button>
    </div>
  )
}
export default App

可以看到上文进行抽离的代码给人的感觉是十分干练整洁的,十分便于维护,结果如下:

RTK QUERY的使用

RTK不仅帮助我们解决了state问题,同时它还为我们提供了RTK Query用来帮助我们处理数据加载问题,RTK Query是一个强大的数据获取和缓存工具,在它的帮助下,Web应用中的加载变得十分简单,它使我们不再需要自己编写虎丘数据和缓存数据的逻辑。

要知道在Web应用中加载数据时需要处理的问题

1)根据不同的加载状态显示不同的UI组件

2)减少对相同数据重复发送请求

3)使用乐观更新,提示用户体验

4)在用户与UI交互时,管理缓存的声明周期

这些问题RTKQ都可以帮助我们处理,首先可以直接通过RTKQ向服务器发送请求加载数据,并且RTKQ会自动对数据进行缓存,避免重复发送不必要的请求,其次RTKQ在发送请求时会根据请求不同的状态返回不同的值,我们可以通过这些值来监视请求发送的过程并随时中止

RTKQ已经继承在了RTK中,如果我们已经在项目中引入了RTK则无需再引入其余的模块,如果你不想使用RTKQ给我们提供的发送请求的方式(简单封装过的fetch),需要自己引入要使用的发送请求的工具。ok接下来开始讲解如何使用RTKQ,如下:

在store文件中新建一个word文件用于获取名言警句的接口,如下:

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' 

// 创建Api对象,createApi()用来创建RTKQ中的API对象
const wordApi = createApi({
  reducerPath:'wordApi', // Api的标识,不能和其他的Api或reducer重复
  baseQuery: fetchBaseQuery({ // 指定查询的基础信息,发送请求使用的工具
    baseUrl:"https://api.uixsj.cn/"
  }), 
  // build是请求的构造器,通过build来设置请求的相关信息
  endpoints(build){
    return {
      getStudents:build.query({
        query(){
          // 用来指定请求的子路径
          return 'hitokoto/get' 
        }
      })
    }
  }
})

// Api对象创建后,对象中会根据各种方法自动是生成对应的钩子函数,通过这些钩子函数,可向服务器发送请求
// 钩子函数的命名规则 getStudents --> useGetStudentsQuery
export const { useGetStudentsQuery } = wordApi
export default wordApi

填写完接口文件后,在store文件夹下的index.jsx文件中进行引入:

import { configureStore } from "@reduxjs/toolkit";
import wordApi from "./word";

const store = configureStore({
  reducer:{
    [wordApi.reducerPath]:wordApi.reducer
  },
  // 添加一个中间件,这个中间件已自动生成了我们直接引入即可,中间件用来处理Api缓存
  middleware:getDefaultMiddleware => {
    return getDefaultMiddleware().concat(wordApi.middleware)
  }
})

export default store

当然这里的话我们也需要在入口文件中进行store传入:

接下来开始使用我们创建的钩子函数进行相关数据的调用,如下:

currentData:undefined  // 当前参数的最新数据

data:undefined              // 最新的数据

isError:false                  // 布尔值,是否有错误

error:Error()                  // 对象,有错时才存在

isFetching:true             // 布尔值,数据是否在加载

isLoading:true              // 布尔值,数据第一次加载成功

isSuccess:false            // 布尔值,请求是否成功

isUninitialized:false      // 布尔值,请求是否还没有开始发送

refetch:f()                     // 一个函数,用来重新加载数据

status:"pending"          // 字符串,请求的状态

因为我调用的接口没有data数据,数据在error中,这里的话需要我们在error进行数据的获取:

import { useGetStudentsQuery } from './store/word'

const App = () => {
  // 调用Api查询数据,这个钩子函数它会返回一个对象作为返回值,请求过程中相关数据都在该对象中
  const {isError,error,isLoading} = useGetStudentsQuery()
  return (
    <div>
      { isLoading && <p>数据加载中...</p> }
      {isError && error.data}
    </div>
  )
}

export default App

如果接收的接口数据有很多,但自己只是想要其中的一小部分,可以通过以下方式解决:

useQuery参数

RTKQ给我们提供对接收到的数据进行自定义设置,如下:

import { useGetStudentsQuery } from './store/word'

const App = () => {
  // 调用Api查询数据,这个钩子函数它会返回一个对象作为返回值,请求过程中相关数据都在该对象中
  const result = useGetStudentsQuery(null,{
    // useQuery可以接收一个对象作为第二个参数,通过该对象可以对请求进行配置
    selectFromResult:result => { // 用来指定useQuery返回的结果
      if(result.data === undefined){
        result.data = '值被我修改了'
      }
      return result
    },
    pollingInterval:0, // 设置轮询的间隔(隔一段时间发起一次请求),单位毫秒,如果为0则不轮询
    skip:false, // 设置是否跳过当前请求,默认为false
    refetchOnMountOrArgChange:false, // 设置是否每次都重新加载数据,false正常使用缓存;true每次都重载数据;数字,数据缓存的时间(秒)
  })
  console.log(result)
  const {isError,error,isLoading} = result
  return (
    <div>
      { isLoading && <p>数据加载中...</p> }
      {isError && error.data}
    </div>
  )
}

还有两个参数设置需要在store进行数据监听才能使用,如下:


http://www.kler.cn/a/15119.html

相关文章:

  • 鸿蒙实战:页面跳转传参
  • 每日OJ题_牛客_天使果冻_递推_C++_Java
  • 独立开发:一人公司模式下副业产品的全流程
  • 搜维尔科技:SenseGlove触觉反馈手套开箱+场景测试
  • Java通过calcite实时读取kafka中的数据
  • 华为刷题笔记--题目索引
  • 快速入门量化交易
  • 数据库管理-第六十九期 另一种累(20230422)
  • 通用el-table 修改样式
  • 【QT5:CAN卡通信的上位机-代码练习-收发数据+布局+引用外部库+基础样例(1)】
  • C++高并发多线程学习
  • 使用QToolButton和QStackedWidget的侧边栏(SideBar)的实现与实现原理解析
  • 力扣---LeetCode88. 合并两个有序数组
  • 面试官:一千万的数据,你是怎么查询的?
  • 科学计算NumPy之Ndarray数组对象的创建、切片、索引、修改等操作汇总
  • 辨析 工作绩效数据、工作绩效信息、工作绩效报告
  • 浏览器环境线程之间的关系
  • C#非常实用的技巧
  • TCP/IP学习总结
  • Python学习之sh(shell脚本)在Python中的使用
  • 手机短信验证码登录功能的开发实录(机器识别码、短信限流、错误提示、发送验证码倒计时60秒)
  • 你不想成长,生活总会逼着你成长,阿里P8架构师分享十年学习生涯
  • 逻辑回归评分系统(mimic数据集)
  • Java设计模式-工厂模式
  • Vue打包后部署缓存问题处理方式
  • HBase正确使用方法