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


    文章目录

    异步逻辑

    createAsyncThunk(一)

    createAsyncThunk(二)

    性能优化

    createSelector


    异步逻辑

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

    如果要让异步逻辑与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” 文件中。

    1. //slices/productSlice.js
    2. import { createSlice } from '@reduxjs/toolkit'
    3. //定义初始state
    4. //list表示商品列表,isLoading表示是否为正在请求数据的状态
    5. const initialState = { list: [] ,isLoading:false}
    6. //创建slice
    7. const slice = createSlice({
    8.    //定义域名称
    9.    name: 'product',
    10.    //传入初始state
    11.    initialState,
    12.    //定义reducers
    13.    reducers: {
    14.        //这个reducer用来把商品数据存储到store中
    15.        addProduct: (state, action) => {
    16. state.list.push(action.payload)
    17.       },
    18.        //这个reducer用来更改isLoading
    19.        changeState:(state,action)=>{
    20.            state.isLoading=action.payload
    21.       }
    22.   }
    23. })
    24. //导出action creator
    25. export const { addProduct ,changeState} = slice.actions
    26. //导出thunk函数
    27. //addProductAsync为thunk函数的创建函数,它返回一个thunk函数
    28. //返回的thunk函数中我们就可以编写异步代码了
    29. export const addProductAsync = (payload) => (dispatch, getState) => {
    30.    //触发action ,改变isLoading的状态
    31.    dispatch(changeState(true))
    32.    setTimeout(() => {
    33.        dispatch(addProduct(payload))
    34.        //触发action ,改变isLoading的状态
    35.        dispatch(changeState(false))
    36.   }, 3000)
    37. }
    38. //导出reducer
    39. export default slice.reducer
    1. //pages/Product.js
    2. import React, { useRef } from 'react';
    3. import { useSelector, useDispatch } from 'react-redux'
    4. import { addProductAsync } from '../slices/productSlice'
    5. //引入thunk函数
    6. export default function Product() {
    7.    const nameRef = useRef()
    8.    const {list:productList,isLoading} = useSelector(state => state.product)
    9.    const dispatch = useDispatch()
    10.    const onAdd = () => {
    11.        //thunk函数的使用,跟普通的action creator的使用一样
    12.    
    13.        dispatch(addProductAsync({ name: nameRef.current.value }))
    14.   }
    15.    return (
    16.        <div>
    17.           我是商品页面<br />
    18.           商品名:<input ref={nameRef} required /><br />
    19.           {isLoading?<div>请求数据中... div>:productList.map((item, index) => <li key={index}>
    20.               商品名:{item.name}
    21.            li>)}
    22.            
    23.            <button onClick={onAdd}>新增商品button>
    24.        div>
    25.   );
    26. }

    createAsyncThunk(一)

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

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

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

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

     在组件中 dispatch thunk

    1. import React, { useRef } from 'react';
    2. import { useSelector, useDispatch } from 'react-redux'
    3. import { addProductPost } from '../slices/productSlice'
    4. //引入thunk函数
    5. export default function Product() {
    6.    const nameRef = useRef()
    7.    const {list:productList,isLoading} = useSelector(state => state.product)
    8.    const dispatch = useDispatch()
    9.    const onAdd = () => {
    10.        //thunk函数的使用,跟普通的action creator的使用一样
    11.    
    12.        dispatch(addProductPost({ name: nameRef.current.value }))
    13.   }
    14.    return (
    15.        <div>
    16.           我是商品页面<br />
    17.           商品名:<input ref={nameRef} required /><br />
    18.           {isLoading?<div>请求数据中...
    19. div>:productList.map((item, index) => <li key={index}>
    20.               商品名:{item.name}
    21.            li>)}
    22.            <button onClick={onAdd}>新增商品button>
    23.        div>
    24.   );
    25. }

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

    1. //slices/productSlice.js
    2. //创建slice
    3. const slice = createSlice({
    4.    //定义域名称
    5.    name: 'product',
    6.    //传入初始state
    7.    initialState,
    8.    //定义reducers
    9.    reducers: {
    10.        //这个reducer用来把商品数据存储到store中
    11.        addProduct: (state, action) => {
    12.            state.list.push(action.payload)
    13.       },
    14.        //这个reducer用来更改isLoading
    15.        changeState:(state,action)=>{
    16.            state.isLoading=action.payload
    17.       }
    18.   },
    19.    //extraReducer设置createAsyncThunk创建的thunk被dispatch后的reducer处理器
    20.    extraReducers(builder){
    21.        builder
    22.       .addCase(addProductPost.pending,(state,action)=>{
    23.            state.isLoading=true
    24.       })
    25.       .addCase(addProductPost.fulfilled,(state,action)=>{
    26.            state.isLoading=false
    27.            state.list.push(action.payload)
    28.       })
    29.   }
    30. })

    createAsyncThunk(二)

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

    1. //slices/productSlice.js
    2. //创建获取商品数据的thunk
    3. export const productListGet = createAsyncThunk('product/productListGet',
    4. async () => {
    5.    const data = await new Promise((resolve, reject) => {
    6.        setTimeout(() => {
    7.            resolve([{ name: '苹果' }, {name: '香蕉' }, { name: "蓝莓" }])
    8.       }, 3000)
    9.   })
    10.    return data
    11. })
    12. extraReducers(builder) {
    13.        builder
    14.           .addCase(addProductPost.pending,(state, action) => {
    15.                state.isLoading = true
    16.           })
    17.           .addCase(addProductPost.fulfilled, (state,action) => {
    18.                state.isLoading = false
    19.               state.list.push(action.payload)
    20.           })
    21.           .addCase(productListGet.pending, (state, action) => {
    22.                state.isLoading = true
    23.           })
    24.           .addCase(productListGet.fulfilled, (state, action) => {
    25.                return { list: action.payload, isLoading: false }
    26.           })
    27.           .addCase(productListGet.rejected, (state,action) => {
    28.                state.isLoading=false
    29.           })
    30.   }
    1. //pages/Product.js
    2. import { addProductPost, productListGet } from '../slices/productSlice'
    3. //组件挂载后请求商品数据
    4. useEffect(() => {
    5.        dispatch(productListGet())
    6.   }, [])

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

    性能优化

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

    1. //pages/ProductChild.js
    2. import React, { useEffect } from 'react';
    3. function ProductChild() {
    4.  
    5.    useEffect(() => {
    6.        console.log('子元素重新渲染')
    7.   })
    8.    return (
    9.        <div>
    10.           子元素
    11.    div>
    12.   );
    13. }
    14. export default React.memo(ProductChild)

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

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

    createSelector

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

     提示:

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

    1. import React, { useEffect } from 'react';
    2. import { useSelector } from 'react-redux';
    3. function ProductChild() {
    4.     const list=useSelector(state=>state.product.list.filter(item=>item.name.length>2))
    5.    useEffect(() => {
    6.        console.log('子元素重新渲染')
    7.   })
    8.    return (
    9.        <div>
    10.           子元素
    11.    div>
    12.   );
    13. }
    14. export default React.memo(ProductChild)

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

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

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

    1. //pages/ProductChild.js
    2. import React, { useEffect } from 'react';
    3. import { useSelector } from 'react-redux';
    4. import {selectList} from '../slices/productSlice'
    5. function ProductChild() {
    6.    // const list=useSelector(state=>state.product.list.filter(item=>item.name.length>2))
    7.   const list=useSelector(selectList)
    8.  
    9.    useEffect(() => {
    10.        console.log('子元素重新渲染')
    11.   })
    12.    return (
    13.        <div>
    14.           子元素
    15.    div>
    16.   );
    17. }
    18. export default React.memo(ProductChild)

  • 相关阅读:
    04 卷积神经网络搭建
    Python3操作Redis最新版|CRUD基本操作(保姆级)
    实现声明式锁,支持分布式锁自定义锁、SpEL和结合事务
    论文解读:《DeepIPs:使用基于深度学习的方法对SARS-CoV-2感染的磷酸化位点进行全面评估和计算识别》
    μC/OS-II---互斥信号量管理1(os_mutex.c)
    mysql 表的操作以及字段的操作总结
    注解配置SpringMVC
    MySQL定时整库备份&滚动删除指定日期前的备份数据
    Java并发工具-4-并发框架(Executor&ForkJoin)
    环保设备用电云监控平台在火力发电厂的应用
  • 原文地址:https://blog.csdn.net/m0_58719994/article/details/134312895