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',
    //传入初始state
    initialState,
    //定义reducers
    reducers: {
        //这个reducer用来把商品数据存储到store中
        addProduct: (state, action) => {
               state.list.push(action.payload)
       },
        //这个reducer用来更改isLoading
        changeState:(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',
    //传入初始state
    initialState,
    //定义reducers
    reducers: {
        //这个reducer用来把商品数据存储到store中
        addProduct: (state, action) => {
            state.list.push(action.payload)
       },
        //这个reducer用来更改isLoading
        changeState:(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=false
            state.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 = false
                state.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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/129889.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3介绍

介绍 3完全兼容2的语法 vue3&#xff1a;体积更小&#xff0c;性能会更高。底层做了很多优化 2倍左右 vue3vitets 渐进式框架 vue3和vue2 的区别 新语法&#xff0c;性能上提升很多 思想是一致的&#xff1a;动态绑定&#xff1a;状态data&计算属性&#xff0c;监听某些状态…

超声波俱乐部分享:Enter AI native application

11月5日&#xff0c;2023年第十四期超声波俱乐部内部分享会在北京望京举行。本期的主题是&#xff1a;Enter AI native application。 到场的嘉宾有&#xff1a;超声波创始人杨子超&#xff0c;超声波联合创始人、和牛商业创始人刘思雨&#xff0c;蓝驰创投合伙人刘勇&#xf…

The Sandbox于香港举办全球首个创作者日,推出「公开发布」功能,并为 GameMakerFund提供1亿$SAND基金!

新的 NFT 铸造、无需编码的 Game Maker 软件升级、其他支持 Web3 创作者的功能优化。 2023 年 11 月 3 日——The Sandbox 举办了首届全球创作者日活动&#xff0c;并在活动期间宣布了其在 2024 年的计划&#xff0c;包括为创作者赋能&#xff0c;在地图上呈现 2000 个用户生成…

说说 React中的setState执行机制

一、是什么 一个组件的显示形态可以由数据状态和外部参数所决定&#xff0c;而数据状态就是state 当需要修改里面的值的状态需要通过调用setState来改变&#xff0c;从而达到更新组件内部数据的作用 如下例子&#xff1a; import React, { Component } from react export d…

flutter 使用 hive 遇到的错误

1. ] Unhandled Exception: RangeError: Not enough bytes available. 根据日志定位到 下图的地方 解决&#xff1a;因为之前存在保存到本地的信息&#xff0c;但是你修改了 数据类里面的东西&#xff08;比如添加变量啥的&#xff09;&#xff0c;清空app缓存或者卸载重新构…

vue2和vue3 的双向绑定原理

前文: 都知道vue是双向绑定的mvvm框架,也一直再用,那么他到底是如何实现的呢?vue3又针对这点做了哪些升级呢? 这段时间也正好有空,下面我们来一起看看吧 一 、vue的双向绑定原理 那么什么是双向绑定呢 ? 一般我们所指的双向绑定都是指的数据,即当数据发生变化的时候,视图也…

Vue简单使用Echart图表柱形图 vue使用柱形图 vue使用 echart图表柱形图 vue使用柱形图

Vue简单使用Echart图表柱形图 vue使用柱形图 vue使用 echart图表柱形图 vue使用柱形图 1、安装依赖2、页面Demo使用3、效果图 1、安装依赖 官方文档&#xff1a;https://echarts.apache.org/zh/option.html#title 官方在线示例&#xff1a;https://echarts.apache.org/exampl…

SpringCloudAlibaba——Nacos

Nacos是服务注册中心服务配置中心。替换了以前的EurekaConfigBus。 1.Nacos作为服务注册中心 Nacos支持AP和CP模式的转换。 2.Nacos作为服务配置中心 服务要配置两个yml文件&#xff0c;bootstrap.yml和application.yml。因为Nacos同springcloud-config一样&#xff0c;在项…

4S店汽车行业万能通用小程序源码系统 在线预约试驾+购车计算器 源码完全开源可二次开发

随着互联网技术的发展和普及&#xff0c;越来越多的消费者开始依赖于互联网进行消费。传统的汽车销售模式也正在经历着数字化转型&#xff0c;以适应消费者需求的变化。这款小程序源码系统就是为帮助汽车4S店等销售商实现数字化转型而开发的。 以下是部分核心功能的代码模块&a…

OushuDB 专家认证第四期报名开始啦!

OushuDB 专家认证培训第四期今日正式启动&#xff01;本次培训为偶数科技面向生态合作伙伴与客户公开举办的线上培训&#xff0c;旨在共同发展 OushuDB 生态。 报名时间&#xff1a;2023年11月9日9:00—11月30日12:00 报名方式&#xff1a;偶数科技官网&#xff08;点击下方阅…

新“芯”向荣|利用合作科研设计和优化电芯案例探究

利用合作科研设计和优化电芯 锂电行业发展的契机——我国致力于减少二氧化碳的排放&#xff0c;将2050年实现净零排放作为目标。 电池制造商、细分领域专用电芯设计厂商、汽车OEM厂商、电动垂直起降(eVTOL)飞机制造商以及电池材料供应商都投入了大量的资源&#xff0c;寻求电…

金融服务行业如何面对精细化的大数据模式下日益增加的文件传输压力?

随着数字化转型的加速&#xff0c;金融机构需要在数据化基础上进行升级和转型&#xff0c;挖掘互联网数据传输与金融业深度融合的新形态&#xff0c;同时确定如何更好地存储、保护和分析数据。然而&#xff0c;在精细化的大数据模式下&#xff0c;金融机构也面临着日益增加的数…

ChatGPT 上新,效果炸裂,知识平台才是大模型的最佳狩猎场

数新网络_让每个人享受数据的价值浙江数新网络有限公司是一家开源开放、专注于云数据智能操作系统和数据价值流通的服务商。公司自主研发的DataCyber云数据智能操作系统&#xff0c;主要包括数据平台CyberData、人工智能平台CyberAI、数据智能引擎CyberEngine、数据安全平台Cyb…

try-catch-finally执行以及他们在有return的情况下,基本数据类型、对象以及有异步赋值情况异同分析

这两天面试,遇到好几个人,都是那种我感觉我肚子里的墨水都吐出来完了,难不倒人家,于是问了下家里那位老狗,从最开始就念叨着你问他try-catch在有return的情况下怎么执行的,执行结果是啥,我前面没理,后面确实有点遭不住了,来看看吧,肚子里添点墨水,别把脸丢大了~ 做…

Android jetpack compose 组件学习

官网地址&#xff1a;https://developer.android.com/jetpack/compose/tutorial?hlzh-cn 一、写一个 hello world 在New Project的时候选择Photo and Tablet里的Empty Compose Activity&#xff0c;如下所示&#xff1a; 打开这个project之后&#xff0c;可以看到MainActivit…

WebSocket魔法师:打造实时应用的无限可能

1、背景 在开发一些前端页面的时候&#xff0c;总是能接收到这样的需求&#xff1a;如何保持页面并实现自动更新数据呢&#xff1f;以往的常规做法&#xff0c;是前端使用定时轮询后端接口&#xff0c;获取响应后重新渲染前端页面&#xff0c;这种做法虽然能达到类似的效果&…

RPC 框架 openfeign 介绍和学习使用总结

一、基本概念 RPC 远程过程调用&#xff08;Remote Procedure Call&#xff09;的缩写形式 Birrell 和 Nelson 在 1984 发表于 ACM Transactions on Computer Systems 的论文《Implementing remote procedure calls》对 RPC 做了经典的诠释。 RPC 是指计算机 A 上的进程&am…

这个平台竟然几秒就可以做出精致的翻页电子画册?

电子画册是现代人生活不可或缺的一部分&#xff0c;它美观大方&#xff0c;二次编辑方便&#xff0c;而且相比于传统纸质画册&#xff0c;电子画册还能够让你拥有更丰富的互动性和视觉体验。如何制作呢&#xff1f; 小编这里要给大家安利的平台是&#xff1a;FLBOOK&#xff0…

腾讯云2023年双11活动:云服务器1.8折起,还可领取9999元代金券!

2023年双11腾讯云推出了11.11云上盛惠大促活动&#xff0c;包括秒杀专区、服务器买赠、新人专区、代金券专区、境外优选、新老同享、续费专区以及热门上云场景等满足新用户、老用户、企业用户对云计算服务的各种需求。 一、腾讯云双11活动地址 活动入口&#xff1a;点此直达 …

vue同时校验多个表单

0 效果 1 代码 checkForm (formRef) {return new Promise((resolve, reject) > {this.$refs[formRef].validate((valid) > {if (valid) {resolve();} else {setTimeout(() > {this.$refs[formRef].clearValidate();reject(new Error(错误));}, 1500);}});}); }, conf…
最新文章