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

React【异步逻辑createAsyncThunk(一)、createAsyncThunk(二)、性能优化、createSelector】(十二)

文章目录

异步逻辑

createAsyncThunk(一)

createAsyncThunk(二)

性能优化

createSelector


异步逻辑

//Product.js
const onAdd = () => {const name = nameRef.current.value// 触发添加商品的事件dispatch(addProduct({name}))
}

如果要让异步逻辑与Store交互,我们需要使用redux middleware。
Redux 有多种异步 middleware,每一种都允许你使用不同的语法编写逻辑。最常见的异步 middleware 是 redux-thunk ,它可以让你编写可能直接包含异步逻辑的普通函数。
Redux Toolkit 的 configureStore 功能默认自动设置 thunk middleware,我们推荐使用 thunk 作为 Redux 开发异步逻辑的标准方式。


Thunk 函数
在Thunk函数中我们可以编写异步逻辑的代码(例如 setTimeout 、Promise 和 async/await ),并且可以通过参数获取到dispatch,getState()。从而在异步操作执行后再diapacth action。
 

提示:
Thunk 通常写在 “slice” 文件中。

//slices/productSlice.js
import { createSlice } from '@reduxjs/toolkit'
//定义初始state
//list表示商品列表,isLoading表示是否为正在请求数据的状态
const initialState = { list: [] ,isLoading:false}
//创建slice
const slice = createSlice({//定义域名称name: 'product',//传入初始stateinitialState,//定义reducersreducers: {//这个reducer用来把商品数据存储到store中addProduct: (state, action) => {state.list.push(action.payload)},//这个reducer用来更改isLoadingchangeState:(state,action)=>{state.isLoading=action.payload}}
})
//导出action creator
export const { addProduct ,changeState} = slice.actions
//导出thunk函数
//addProductAsync为thunk函数的创建函数,它返回一个thunk函数
//返回的thunk函数中我们就可以编写异步代码了
export const addProductAsync = (payload) => (dispatch, getState) => {//触发action ,改变isLoading的状态dispatch(changeState(true))setTimeout(() => {dispatch(addProduct(payload))//触发action ,改变isLoading的状态dispatch(changeState(false))}, 3000)
}//导出reducer
export default slice.reducer
//pages/Product.js
import React, { useRef } from 'react';
import { useSelector, useDispatch } from 'react-redux'
import { addProductAsync } from '../slices/productSlice'
//引入thunk函数
export default function Product() {const nameRef = useRef()const {list:productList,isLoading} = useSelector(state => state.product)const dispatch = useDispatch()const onAdd = () => {//thunk函数的使用,跟普通的action creator的使用一样dispatch(addProductAsync({ name: nameRef.current.value }))}return (<div>我是商品页面<br />商品名:<input ref={nameRef} required /><br />{isLoading?<div>请求数据中... </div>:productList.map((item, index) => <li key={index}>商品名:{item.name}</li>)}<button onClick={onAdd}>新增商品</button></div>);
}

createAsyncThunk(一)

 Redux Toolkit 的 createAsyncThunk API 生成 thunk,为你自动 dispatch 那些 "状态" action。

 createAsyncThunk 接收 2 个参数:
1、 参数一:将用作生成的 action type的前缀的字符串
2 、一个 “payload creator” 回调函数,它应该返回一个 Promise 或者其他数据

 //slices/productSlice.js
//使用createAsyncThunk创建thunk
//接收的第一个参数是action 的 type的前缀
//第二个参数是一个函数,用来返回payload
export const addProductPost = createAsyncThunk('product/addProductPost', (item)=>{return  new Promise((resolve,reject)=>{setTimeout(()=>{resolve(item)},3000)})
})

提示:
当调用 dispatch(addProductPost()) 的时候, addProductPost 这个 thunk 会
首先 dispatch 一个 action 类型为 'product/addProductPost/pending'
当异步代码执行完,返回的Promise resove后会dispatch 一个
action 类型为 product/addProductPost/fulfilled

 在组件中 dispatch thunk

import React, { useRef } from 'react';
import { useSelector, useDispatch } from 'react-redux'
import { addProductPost } from '../slices/productSlice'
//引入thunk函数
export default function Product() {const nameRef = useRef()const {list:productList,isLoading} = useSelector(state => state.product)const dispatch = useDispatch()const onAdd = () => {//thunk函数的使用,跟普通的action creator的使用一样dispatch(addProductPost({ name: nameRef.current.value }))}return (<div>我是商品页面<br />商品名:<input ref={nameRef} required /><br />{isLoading?<div>请求数据中...</div>:productList.map((item, index) => <li key={index}>商品名:{item.name}</li>)}<button onClick={onAdd}>新增商品</button></div>);}

添加extraReducers
extraReducers可以监听createAsyncThunk创建的action被 dispatch。
 

//slices/productSlice.js
//创建slice
const slice = createSlice({//定义域名称name: 'product',//传入初始stateinitialState,//定义reducersreducers: {//这个reducer用来把商品数据存储到store中addProduct: (state, action) => {state.list.push(action.payload)},//这个reducer用来更改isLoadingchangeState:(state,action)=>{state.isLoading=action.payload}},//extraReducer设置createAsyncThunk创建的thunk被dispatch后的reducer处理器extraReducers(builder){builder.addCase(addProductPost.pending,(state,action)=>{state.isLoading=true}).addCase(addProductPost.fulfilled,(state,action)=>{state.isLoading=falsestate.list.push(action.payload)})}
})

createAsyncThunk(二)

 提示:
createAsyncThunk 自动生成 pending/fulfilled/rejected action 类型

//slices/productSlice.js
//创建获取商品数据的thunk
export const productListGet = createAsyncThunk('product/productListGet',
async () => {const data = await new Promise((resolve, reject) => {setTimeout(() => {resolve([{ name: '苹果' }, {name: '香蕉' }, { name: "蓝莓" }])}, 3000)})return data
})
extraReducers(builder) {builder.addCase(addProductPost.pending,(state, action) => {state.isLoading = true}).addCase(addProductPost.fulfilled, (state,action) => {state.isLoading = falsestate.list.push(action.payload)}).addCase(productListGet.pending, (state, action) => {state.isLoading = true}).addCase(productListGet.fulfilled, (state, action) => {return { list: action.payload, isLoading: false }}).addCase(productListGet.rejected, (state,action) => {state.isLoading=false})}
//pages/Product.js
import { addProductPost, productListGet } from '../slices/productSlice'
//组件挂载后请求商品数据
useEffect(() => {dispatch(productListGet())}, [])

提示:
Immer 让我们以两种方式更新状态:要么 更新 现有状态值,要么 return 一个新结果。
如果我们返回一个新值,它将用我们返回的任何内容完全替换现有状态。

性能优化

 React.memo()
React 的默认行为是当父组件渲染时,React 会递归渲染其中的所有子组件!

//pages/ProductChild.js
import React, { useEffect } from 'react';
function ProductChild() {useEffect(() => {console.log('子元素重新渲染')})return (<div>子元素</div>);
}
export default React.memo(ProductChild)

为了让子组件跳过没有必要的渲染,我们可以将 子组件包装在 React.memo() 中,这可以确保组件只有在 props 真正更改时才会重新渲染。
 

//pages/ProductChild.js
export default React.memo(ProductChild)

createSelector

 如果子组件中使用了useSelector来获取数据,也会存在一些不必要的渲染。

 提示:

一般情况下,只要我们dispatch 了 action,store发生了变更之后,那么传递给useSelector的选择器器就会被重新调用,如果选择器返回的结果跟原来的状态不一样,则组件重新被渲染。

import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';
function ProductChild() {const list=useSelector(state=>state.product.list.filter(item=>item.name.length>2))useEffect(() => {console.log('子元素重新渲染')})return (<div>子元素</div>);
}
export default React.memo(ProductChild)

我们可以使用 createSelector 来定义有记忆的选择器。
 

//slices/productSlice.js
import { createSelector} from '@reduxjs/toolkit'
export const selectList= createSelector([state =>{    return state.product.list
} ], (list) => {console.log('重新计算list')return list.filter(item=>item.name.length>2)
})

createSelector函数可以接收N-1个输入函数,一个输出函数(最终的选择器),前面的N-1个输入函数的参数由调用输出函数的时候传入的参数决定,输出函数的参数由前面N-1个输入函数的返回值决定。只有当输出函数的参数发生了变更,输出函数才会被重新执行。

//pages/ProductChild.js
import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';
import {selectList} from '../slices/productSlice'
function ProductChild() {// const list=useSelector(state=>state.product.list.filter(item=>item.name.length>2))const list=useSelector(selectList)useEffect(() => {console.log('子元素重新渲染')})return (<div>子元素</div>);
}
export default React.memo(ProductChild)

相关文章:

React【异步逻辑createAsyncThunk(一)、createAsyncThunk(二)、性能优化、createSelector】(十二)

文章目录 异步逻辑 createAsyncThunk&#xff08;一&#xff09; createAsyncThunk&#xff08;二&#xff09; 性能优化 createSelector 异步逻辑 //Product.js const onAdd () > {const name nameRef.current.value// 触发添加商品的事件dispatch(addProduct({name…...

Halcon WPF 开发学习笔记(3):WPF+Halcon初步开发

文章目录 前言在MainWindow.xaml里面导入Halcon命名空间WPF简单调用Halcon创建矩形简单调用导出脚本函数 正确显示匹配效果 前言 本章会简单讲解如何调用Halcon组件和接口&#xff0c;因为我们是进行混合开发模式。即核心脚本在平台调试&#xff0c;辅助脚本C#直接调用。 在M…...

P6入门:项目初始化9-项目详情之资源 Resource

前言 使用项目详细信息查看和编辑有关所选项目的详细信息&#xff0c;在项目创建完成后&#xff0c;初始化项目是一项非常重要的工作&#xff0c;涉及需要设置的内容包括项目名&#xff0c;ID,责任人&#xff0c;日历&#xff0c;预算&#xff0c;资金&#xff0c;分类码等等&…...

Python高级语法----使用Python进行模式匹配与元组解包

文章目录 1. 模式匹配的新特性2. 高级元组解包技巧3. 数据类的匹配与应用1. 模式匹配的新特性 Python自3.10版本起引入了结构化模式匹配的新特性,这是一种强大的工具,允许开发者用更清晰、更直观的方式处理数据结构。模式匹配类似于其他编程语言中的switch-case语句,但它更…...

MySQL安装配置与使用教程(2023.11.13 MySQL8.0.35)

CONTENTS 1. MySQL的安装与配置2. MySQL常用操作教程 1. MySQL的安装与配置 MySQL Windows Installer 下载地址&#xff1a;MySQL Installer。 我们下载最新版本&#xff08;目前是8.0.35&#xff09;的安装包&#xff0c;注意要选择更大的那个&#xff0c;名字为 mysql-inst…...

【阿里云数据采集】采集标准Docker容器日志:部署阿里云Logtail容器以及创建Logtail配置,用于采集标准Docker容器日志

文章目录 引言I 预备知识1.1 Logtail1.2 安装Logtail1.3 创建用户自定义标识机器组1.4 设置logtail容器组件重启策略II 采集服务器日志2.1 采集同一账号下同地域服务器的日志2.2 不同账号下同地域服务器的日志2.3 创建Logtail配置III 查询语法3.1 具体查询语法3.2 查询示例3.3 …...

Django中如何创建表关系,请求生命周期流程图

Django中ORM创建表关系 如何创建表关系(一对一 &#xff0c; 一对多 &#xff0c; 多对多) 图书表&#xff0c;出版社表&#xff0c;作者表&#xff0c;作者详情表 换位思考法判断表关系 图书表和出版社表 >>> 一对多 >>> 图书表是多&#xff0c;出…...

MongoDB副本集配置和创建

副本集有三类角色&#xff1a;master(primary)&#xff0c;slave(secondary)&#xff0c;仲裁服务器。 primary是主&#xff0c;只有primary能写入&#xff0c;secondary无法插入数据&#xff0c;且需要声明是slave才能查看数据 一般生产搞三个服务器做一个master和两个slave&a…...

使用 `open-uri.with_proxy` 方法打开网页

Ruby 爬虫程序如下&#xff1a; require open-uri require nokogiri# 定义代理信息 proxy_host jshk.com.cn# 定义要爬取的网页 URL url http://www.example.com# 使用代理信息打开网页 open-uri.with_proxy(proxy_host, proxy_port) do |proxy|# 使用 Nokogiri 库解析网页内…...

数据库表的设计——范式

目录 1. 设计数据表需要注意的点 2. 范式 2.1 范式简介 2.2 范式有哪些&#xff1f; 2.3 第一范式(1NF) 2.4 第二范式(2NF) 2.5 第三范式(3NF) 2.6 小结 1. 设计数据表需要注意的点 &#xff08;1&#xff09;首先要考虑设计这张表的用途&#xff0c;这张表都要存放什…...

Brute Force

Brute Force "Brute Force"&#xff08;暴力破解&#xff09;指的是一种通过尝试所有可能的组合来获取访问、解密或破解信息的攻击方法。这种攻击方法通常是基于暴力和不断尝试的&#xff0c;不依赖漏洞或弱点。通常用于破解密码、破坏系统或获取未经授权的访问权限…...

HTML简单介绍

且视他人之疑目如盏盏鬼火&#xff0c;大胆地去你的夜路。 目录 1.网页 2.Web标准 3.HTML 3.1HTML结构 3.2HTML标签​编辑 4.标签介绍 4.1排版标签 4.2文本格式化标签 4.3媒体标签 4.3.1图片标签 4.3.2 音频标签 4.3.3视频标签 5.相对路径 6.链接标签 6.1target属…...

【Java笔试强训】Day10(CM62 井字棋、HJ87 密码强度等级)

CM62 井字棋 链接&#xff1a;井字棋 题目&#xff1a; 给定一个二维数组board&#xff0c;代表棋盘&#xff0c;其中元素为1的代表是当前玩家的棋子&#xff0c;0表示没有棋子&#xff0c;-1代表是对方玩家的棋子。当一方棋子在横竖斜方向上有连成排的及获胜&#xff08;及…...

C语言求数组中出现次数最多的元素

一、前言 遇到一个需求&#xff0c;需要求数组中出现次数最多的元素&#xff0c;查找了一些资料&#xff0c;结合自己的思路&#xff0c;编写了程序并验证。 只考虑元素为非负整数的数组&#xff0c;如果有出现次数相同的元素&#xff0c;则返回较小元素。 二、编程思路 以数…...

【Python Opencv】Opencv画图形

文章目录 前言一、画图形1.1 画线1.2 画矩形1.3 画圆1.4 画椭圆1.5 添加文本 总结 前言 在计算机视觉和图像处理中&#xff0c;OpenCV不仅可以处理图像和视频&#xff0c;还提供了一组功能强大的工具&#xff0c;用于在图像上绘制各种形状和图形。这些功能使得我们能够在图像上…...

了解防抖和节流:提升前端交互体验的实用策略

了解防抖和节流&#xff1a;提升前端交互体验的实用策略 前言什么是防抖&#xff1f;什么是节流&#xff1f;应用实例防抖实例节流实例 前言 本文将重点介绍前端性能优化方法之一的防抖和节流。首先解释了它们的概念和原理&#xff0c;然后探讨了它们在前端开发中的应用场景&a…...

SQL学习之增删改查

文章目录 数据库数据类型建表create table插入数据insert into查询数据select from修改数据update set删除数据delete from备份ctas结果插入iis截断表 truncate table修改表结构alter table添加注释 注&#xff1a;本文的SQL语法是基于Oracle数据库操作的&#xff0c;但是基本的…...

Ansible角色定制实例

目录 角色定制&#xff1a;roles 角色定制实例&#xff1a;利用角色部署wordpress 1.在roles目录下生成对应的目录结构 2.定义配置文件 ①nginx ②php ③mysql ④定义剧本文件 ⑤启动服务 角色定制&#xff1a;roles 对于普通的剧本&#xff08;playbook&#xff09;有…...

ElastaticSearch--- es多字段聚合

在使用es时&#xff0c;我们经常会用到聚合查询。 简单的聚合查询&#xff0c;已经在前面介绍过&#xff0c;详情见&#xff1a; https://www.cnblogs.com/expiator/p/13843969.html 有时&#xff0c;也会用到多字段聚合查询。类似于Mysql的Group By多个字段。 比如&#xf…...

本周Github有趣开源项目:Rspress等6个

Github有趣的项目、工具和库&#xff1a; 1、sshx 一个基于 Web 的安全协作终端。通过网络进行快速、协作的实时终端共享 特征&#xff1a; 运行一个命令即可与任何人共享您的终端。 在无限画布上调整大小、移动窗口以及自由缩放和平移。 查看其他人的光标实时移动。 连接到…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...