React immer与Redux Toolkit使用教程详解

目录
  • 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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Immer 功能最佳实践示例教程

    目录 一.前言 二.学习前提 三.历史背景 四.immer 功能介绍 好处 更新模式 更新对象 更新数组 嵌套数据结构 异步 producers & createDraft createDraft 和 finishDraft 五.性能提示 预冻结数据 可以随时选择退出 对于性能消耗大的的搜索操作,从原始 state 读取,而不是 draft 将 produce 拉到尽可能远的地方 六.陷阱 不要重新分配 recipe 参数 Immer 只支持单向树 永远不要从 producer 那里显式返回 u

  • Android ShimmerLayout实现微光效果解析

    前阵子在github上看到一个很不错的动画效果,叫做ShimmerLayout,是一个用于实现内部视图微光效果的布局. 如何实现 通过使用PorterDuff,我们可以制造出微光效果.PorterDuff是canvas绘制图像处理中的一种渲染模式,当我们需要绘制出区域覆盖的图形效果的时候,我们可以使用这种方式来绘制. 这里我们采用的是PorterDuff.MODE.SRC_IN,意思是在绘制的时候,显示上下图层相交的部分,且这部分显示上层图层. 1) 首先我们需要绘制出最上层的微光,这里通过Li

  • React immer与Redux Toolkit使用教程详解

    目录 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状态管理Redux的使用介绍详解

    目录 1. 简介 2. 核心概念 3. redux工作流 4. 模拟redux工作流程 5. 使用redux 6. react-redux 1. 简介 Redux 是 JavaScript 应用的状态容器(对象),提供可预测的状态管理.可以让你开发出行为稳定可预测的应用,运行于不同的环境(客户端.服务器.原生应用),并且易于测试.Redux 除了和 React 一起用外,还支持其它界面库. 解决的问题:多层级组件间通信问题. 2. 核心概念 单一数据源 整个redux中的数据都是集中管理,存储于

  • React开发进阶redux saga使用原理详解

    目录 前言 redux的特点 分析原理 1. 自动执行Generator 2. 发布订阅模式 3. put, takeEvery, delay, call返回effect 总结 前言 工作中使用了redux-saga这个redux中间件,如果不明白内部原理使用起来会让人摸不着头脑,阅读源码后特意对其原理做下总结. redux的特点 一个标准.管理应用副作用的redux中间件 实现切面编程方式 声明式的编写方式 订阅发布的设计模式 优点: 把异步操作转移到单独 saga文件中,而不是糅杂在acti

  • React为 Vue 引入容器组件和展示组件的教程详解

    如果你使用过 Redux 开发 React,你一定听过 容器组件(Smart/Container Components) 或 展示组件(Dumb/Presentational Components),这样划分有什么样的好处,我们能否能借鉴这种划分方式来编写 Vue 代码呢?这篇文章会演示为什么我们应该采取这种模式,以及如何在 Vue 中编写这两种组件. 为什么要使用容器组件? 假如我们要写一个组件来展示评论,在没听过容器组件之前,我们的代码一般都是这样写的: components/Comment

  • React高阶组件使用教程详解

    目录 高阶组件(HOC) 概述 使用HOC解决横切关注点问题 不用改变原始组件使用组合 约定-将不相关的 props 传递给被包裹的组件 约定-最大化可组合性 约定-包装显示名称以便轻松调试 使用高阶组件的注意事项 高阶组件(HOC) 概述 是React复用组件逻辑的一种高级技巧,是一种基于React组合特性而形成的设计模式 高阶组件是参数为组件,返回值为新组件的函数 简单理解: 高阶组件本身是 函数,传参数是组件,返回值也是组件: 高阶组件不用关心数据是如何渲染的,只用关心逻辑即可 被包装的组

  • React redux 原理及使用详解

    目录 概述 createStore创建store applyMiddleware 应用中间件 combineReducers 合并多个reducer dispatch 中间件 中间件的调用顺序 store redux 数据流 bindActionCreators compose enhancer 使用 redux 常遇见的问题 概述 一个状态管理工具 Store:保存数据的地方,你可以把它看成一个容器,整个应用只能有一个 Store. State:包含所有数据,如果想得到某个时点的数据,就要对

  • windows上安装Anaconda和python的教程详解

    一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因此,我们这里使用Python这个脚本语言来进行数字图像处理. 要使用Python,必须先安装python,一般是2.7版本以上,不管是在windows系统,还是Linux系统,安装都是非常简单的. 要使用python进行各种开发和科学计算,还需要安装对应的包.这和matlab非常相似,只是matla

  • 使用Vue开发动态刷新Echarts组件的教程详解

    需求背景:dashboard作为目前企业中后台产品的"门面",如何更加实时.高效.炫酷的对统计数据进行展示,是值得前端开发工程师和UI设计师共同思考的一个问题.今天就从0开始,封装一个动态渲染数据的Echarts折线图组件,抛砖引玉,一起来思考更多有意思的组件. 准备工作 项目结构搭建 因为生产需要(其实是懒),所以本教程使用了 ==vue-cli==进行了项目的基础结构搭建. npm install -g vue-cli vue init webpack vue-charts cd

  • TensorFlow的环境配置与安装教程详解(win10+GeForce GTX1060+CUDA 9.0+cuDNN7.3+tensorflow-gpu 1.12.0+python3.5.5)

    记录一下安装win10+GeForce GTX1060+CUDA 9.0+cuDNN7.3+tensorflow-gpu 1.12.0+python3.5.5 之前已经安装过pycharm.Anaconda以及VS2013,因此,安装记录从此后开始 总体步骤大致如下: 1.确认自己电脑显卡型号是否支持CUDA(此处有坑) 此处有坑!不要管NVIDIA控制面板组件中显示的是CUDA9.2.148. 你下载的CUDA不一定需要匹配,尤其是CUDA9.2,最好使用CUDA9.0,我就在此坑摔的比较惨.

  • React三大属性之props的使用详解

    上期讲了state,接下来讲讲props.props功能在于组件间通信(父子组件),首先说说在各种组件中的用法: 类组件 //父组件传值 class Father extends React.PureComponent{ render(){ return ( <Son value={"son"} /> ) } } class Son extends React.PureComponent{ render(){ return ( <div>this data is

随机推荐