当前位置 : 主页 > 网络编程 > JavaScript >

React immer与Redux Toolkit使用教程详解

来源:互联网 收集:自由互联 发布时间:2023-02-08
目录 1. immer 1.1 setState结合immer使用 1.2 useState结合immer使用 1.3 immer和redux集合 2. Redux Toolkit 1. immer 概述: 它和immutable相似的,实现了操作对象的数据共享,可以优化性能。它实现的原理使
目录
  • 1. immer
    • 1.1 setState结合immer使用
    • 1.2 useState结合immer使用
    • 1.3 immer和redux集合
  • 2. Redux Toolkit

    1. immer

    概述:

    它和immutable相似的,实现了操作对象的数据共享,可以优化性能。它实现的原理使用es6的Proxy完成的。小巧,没有像immutable哪样有新数据类型,而是使用js类型。

    安装:

    yarn add immer@9

    1.1 setState结合immer使用

    简单使用:

    import React from 'react'
    // 把源数据使用Proxy进行代理处理,后面就可以精准的去找到变化的数据
    import { produce } from 'immer'
    const state = {
      count: 1
    }
    // 进行代理后,并修改
    // draft就是代理对象,它就是state代理对象
    const newState = produce(state, draft => {
      draft.count++
    })
    console.log(newState.count)// 2
    const App = () => {
      return <div></div>
    }
    export default App

    使用immer进行proxy代理,源数据中只有变化的了的数据才更新,没有变化则共享,这样做可以提高性能:

    import React from 'react'
    // 把源数据使用Proxy进行代理处理,后面就可以精准的去找到变化的数据
    import { produce } from 'immer'
    const baseState = {
      arr: [1, 2, 3],
      obj: { id: 1, name: '张三' }
    }
    // 使用immer进行proxy代理,源数据中只有变化的了的数据才更新,没有变化则共享,提高性能
    const newState = produce(baseState, draft => {
      draft.arr.push(4)
    })
    // 当前只修改数组,对象没有修改,共享
    console.log('arr', newState.arr === baseState.arr) // false
    console.log('obj', newState.obj === baseState.obj) // true
    const App = () => {
      return <div></div>
    }
    export default App

    使用 immer 优化 setState 使用:

    import React, { Component } from 'react'
    import { produce } from 'immer'
    // 优化setState更新数据
    class App extends Component {
      state = {
        count: 100,
        carts: [
          { id: 1, name: 'aa', num: 1 },
          { id: 2, name: 'bb', num: 2 }
        ]
      }
      addCount = () => {
        // 原来的写法
        // this.setState(state => ({ count: state.count + 1 }))
        // 使用immer来优化setState操作
        this.setState(
          produce(draft => {
            // 不用返回,返加不允许,draft它是一个代理对象,修改后,它能监听到数据的变化,更新视图
            draft.count++
          })
        )
      }
      render() {
        return (
          <div>
            <h3>{this.state.count}</h3>
            <button onClick={this.addCount}>++++++</button>
            <hr />
            {this.state.carts.map((item, index) => (
              <li key={item.id}>
                <span>{item.name}</span>
                <span>---</span>
                <span>
                  {item.num} --
                  <button
                    onClick={() => {
                      this.setState(
                        produce(draft => {
                          // draft它就是当前的this.state
                          draft.carts[index].num++
                        })
                      )
                    }}
                  >
                    ++++
                  </button>
                </span>
              </li>
            ))}
          </div>
        )
      }
    }
    export default App

    1.2 useState结合immer使用

    import React, { useState } from 'react'
    import { produce } from 'immer'
    const App = () => {
      // 普通的数字,不是proxy代理,proxy代理的是对象
      // 如果它是一个普通值,没有必要使用immer来完成优化操作
      let [count, setCount] = useState(100)
      // 对象类型才是使用immer工作的场景
      let [carts, setCarts] = useState([
        { id: 1, name: 'aa', num: 1 },
        { id: 2, name: 'bb', num: 2 }
      ])
      return (
        <div>
          <h3>{count}</h3>
          <button
            onClick={() => {
              // 之前的写法
              // setCount(v => v + 1)
              setCount(produce(draft => draft + 1))
            }}
          >
            +++count+++
          </button>
          <hr />
          <button
            onClick={() => {
              setCarts(
                produce(draft => {
                  draft.push({ id: Date.now(), num: 1, name: 'aaaa--' + Date.now() })
                })
              )
            }}
          >
            添加商品
          </button>
          {carts.map((item, index) => (
            <li key={item.id}>
              <span>{item.name}</span>
              <span>---</span>
              <span>
                {item.num} --
                <button
                  onClick={() => {
                    setCarts(
                      produce(draft => {
                        // 不能返回,写上去感觉就像在vue的感觉
                        draft[index].num++
                      })
                    )
                  }}
                >
                  ++++
                </button>
              </span>
              <span
                onClick={() => {
                  setCarts(
                    produce(draft => {
                      draft.splice(index, 1)
                    })
                  )
                }}
              >
                删除
              </span>
            </li>
          ))}
        </div>
      )
    }
    export default App
    

    1.3 immer和redux集合

    redux/index.js:

    import { createStore } from 'redux'
    import { produce } from 'immer'
    const initState = {
      count: 100
    }
    // 以前的写法
    /* const reducer = (state = initState, { type, payload }) => {
      if ('add' === type) {
        // 深复制
        return { ...state, count: state.count + payload }
      }
      return state
    } */
    const reducer = produce((draft, { type,  payload }) => {
      // 写法就和vuex中的mutation中的写法一样的,简化了
      // 操作数据无需深复制,提升性能
      if ('add' === type) draft.count += payload
    }, initState)
    export default createStore(reducer)

    前端页面:

    import React from 'react'
    import { useSelector, useDispatch } from 'react-redux'
    const App = () => {
      const dispatch = useDispatch()
      const count = useSelector(state => state.count)
      return (
        <div>
          <h3>{count}</h3>
          <button
            onClick={() => {
              dispatch({ type: 'add', payload: 2 })
            }}
          >
            ++++
          </button>
        </div>
      )
    }
    export default App

    2. Redux Toolkit

    概述:

    它开箱即用的高效 Redux 开发工具集,是 redux 新的库,也是官方推荐今后在项目中使用的 redux 库,内置了immer、redux-thunk和redux-devtools。

    安装:

    yarn add @reduxjs/toolkit react-redux

    使用:

    前台页面:

    import React from 'react'
    import { useSelector, useDispatch } from 'react-redux'
    const App = () => {
      const dispatch = useDispatch()
      const count = useSelector(state => state.count)
      return (
        <div>
          <h3>{count}</h3>
          <button
            onClick={() => {
              dispatch({ type: 'add', payload: 2 })
            }}
          >
            ++++
          </button>
        </div>
      )
    }
    export default App

    redux入口文件:

    import { configureStore } from '@reduxjs/toolkit'
    // 上来它就是分模块,在项目中,所以的数据一定是分模块来管理的
    import count from './modules/count'
    import user from './modules/users'
    export default configureStore({
      reducer: {
        count,
        user
      }
    })

    同步操作(count.js):

    import { createSlice } from '@reduxjs/toolkit'
    // 同步操作
    const countSlice = createSlice({
      // 命名空间名称,比redux中更好,redux没有
      // 它的名称要和入口文件中configureStore中的reducer配置对象中的key名称要一致
      name: 'count',
      // 初始化数据源
      initialState: {
        num: 10 
      },
      // 修改数据源的方法集合
      reducers: {
        // 组件中派发dispatch(setNum(2)) // 2就会给payload
        // state它就是proxy对象[immer]
        setNum(state, { payload }) {
          state.num += payload
        }
      }
    })
    // 导出给在组件中调用
    export const { setNum } = countSlice.actions
    // 把当前模块的reducer导入,集合到大的reducer中
    export default countSlice.reducer

    异步操作(users.js):

    import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
    // 方案2
    // 写在上面,进行网络请求
    export const fetchUser = createAsyncThunk('user/fetchUser', async page => {
      // 实现异步数据获取
      let ret = await (await fetch('/api/users?page=' + page)).json()
      // return 中的数据就是返回到state中的users中的数据  一定要return
      return ret.data
    })
    // 异步操作
    const userSlice = createSlice({
      name: 'user',
      initialState: {
        users: []
      },
      reducers: {
        setUsers(state, { payload }) {
          state.users = payload
        }
      },
      // 解决异步
      extraReducers: builder => {
        // 模拟了promise的3个状态,只取成功状态 fulfilled
        // payload中的数据就是fetchUser方法它return出来的数据
        builder.addCase(fetchUser.fulfilled, (state, { payload }) => {
          state.users = payload
        })
      }
    })
    export const { setUsers } = userSlice.actions
    // 网络请求  --- 内置redux-thunk所以,就可以在此处完成异步操作  -- 我推荐的
    // 方案1
    export const fetchThunkUser = () => async dispatch => {
      let ret = await (await fetch('/api/users')).json()
      dispatch(setUsers(ret.data))
    }
    export default userSlice.reducer

    到此这篇关于React immer与Redux Toolkit使用教程详解的文章就介绍到这了,更多相关React immer与Redux Toolkit内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!

    上一篇:element表单使用校验之校验失效问题详解
    下一篇:没有了
    网友评论