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

文章目录

异步逻辑

createAsyncThunk(一)

createAsyncThunk(二)

性能优化

createSelector


异步逻辑

React【异步逻辑createAsyncThunk(一)、createAsyncThunk(二)、性能优化、createSelector】(十二)_第1张图片

//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 (
        
          我是商品页面
          商品名:
          {isLoading?
请求数据中...
:productList.map((item, index) =>
  •               商品名:{item.name}            
  • )}                                
      ); }

    createAsyncThunk(一)

    React【异步逻辑createAsyncThunk(一)、createAsyncThunk(二)、性能优化、createSelector】(十二)_第2张图片

     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 (
            
              我是商品页面
              商品名:
              {isLoading?
    请求数据中...
    :productList.map((item, index) =>
  •               商品名:{item.name}            
  • )}                    
      ); }

    添加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(二)

    React【异步逻辑createAsyncThunk(一)、createAsyncThunk(二)、性能优化、createSelector】(十二)_第3张图片

     提示:
    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【异步逻辑createAsyncThunk(一)、createAsyncThunk(二)、性能优化、createSelector】(十二)_第4张图片

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

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

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

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

    createSelector

    React【异步逻辑createAsyncThunk(一)、createAsyncThunk(二)、性能优化、createSelector】(十二)_第5张图片

     如果子组件中使用了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 (
            
              子元素    
      ); } 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 (
            
              子元素    
      ); } export default React.memo(ProductChild)

    你可能感兴趣的:(java,前端,服务器,React)