这种情况下如果用 setState({…}) 这种形式的话修改数据的话会比较麻烦,所以推荐函数式写法:

this.setState(state => {
    state.people[2].englishName = 'Robin Lee'
    return {...state}
});

函数式setState写法要求每次都返回一个新的引用,在类组件走遍天下的那个时代,state这个变量几乎存储了此组件中的所有数据,便于集中访问与管理。

Hooks时代

用了函数式组件定义数据就不能再这么定义了,假如你要是还像以前一样那么写:

const [state, setState] = useState({
    people: [
        name: '马云',
        englishName: 'Jack Ma'
        name: '马化腾',
        englishName: 'Pony Ma'
        name: '李彦宏',
        englishName: 'Robin Li'
});

那么你的setState就不太好改了,相信用过React Hooks的小伙伴们都能懂,而且这也不是被推荐的写法,一般来说我们会尽可能的细分:

const [jack, setJack] = useState({
    name: '马云',
    englishName: 'Jack Ma'
});
const [pony, setPony] = useState({
    name: '马化腾',
    englishName: 'Pony Ma''
});
const [robin, setRobin] = useState({
    name: '李彦宏',
    englishName: 'Robin Li'
});

这样的话修改数据就方便多了,粒度也更细腻,但是就是写起来麻烦、不够直观、代码量也更多,尤其是当你的数据量比较大、或者嵌套层级比较深的情况下那简直就是一场灾难。

那么怎么样才能既像以前setState那样方便快捷,同时又能使用函数式组件呢?聪明的朋友们应该猜也猜到了:useImmer

use-immer

来看看useImmer是怎么撰写上述逻辑的:

// 定义
const [state, setState] = useImmer({
    people: [
        name: '马云',
        englishName: 'Jack Ma'
        name: '马化腾',
        englishName: 'Pony Ma'
        name: '李彦宏',
        englishName: 'Robin Li'
// 修改
setState(state => {state.people[2].name = 'Robin Lee'})

无论嵌套层级多么深,无论数据有多么复杂,useImmer总能让你找到当年 this.setState(state => state.people[2].name = ‘Robin Lee’) 的感觉,但是不同之处除了一个要用 this. 而另一个不用以外还有一个需要注意的地方:

原生的setState直接可以当作返回值,而这个useImmer生成的盗版useState修改后的值不能被直接当作返回值返回,所以需要在函数体外面有大括号。
当然也可以自定义返回值,返回什么值就会更新成什么值。

喜欢我文章的朋友记得关注+点赞啊!

$ yarn add use-state-as-array import useStateAsArray from 'use-state-as-array' ; const [ stateAsArray , setStateAsArray ] = useStateAsArray ( [ 'first' , 'second' ] ) setStateAsArray ( 0 , 'new value' ) useImmer useImmer(initialState)与非常相似。 该函数返回一个元组,该元组的第一个值是当前状态,第二个是更新程序功能,该功能接受一个或一个值作为参数。 使用沉浸式生成器功能管理状态 将函数传递给更新程序时,可以自由更改draft参数,直到生产者结束并且更改将变为不可变并成为下一个状态。 示例: : import React from "react" ; import { useImmer } from "use-immer" ; function App ( ) { const [ person , updatePerson ] = useImmer ( { name : "Michel" , age : 3 如果一次重新渲染导致某些依赖项发生了改变,或你没有提供这个参数列表,你的函数 createHandle 将会被重新执行,而新生成的句柄则会被分配给 ref。参数一:计算要缓存的值的函数。同样,并不是所有的记忆都是有效的:一个“总是新的”的值就足以破坏整个组件的记忆。一般来说,我们最好是在真实环境中测试组件,但对于复杂的状态更新逻辑,针对特定的初始状态和 action,断言 reducer 返回的特定状态会很有帮助。如果有足够的空间,工具提示应该出现在元素的上方,但如果它不合适,它应该出现在元素的下方。 import React, { useState, useEffect, useReducer } from 'react';import { useImmer } from "use-immer"import './App.css';function reducer(state: { count: number; }, action: { type: any; }) {switch (actio... react hooks 是 React 16.8 的新增特性。 它可以让我们在函数组件中使用 state 、生命周期以及其他 react特性,而不仅限于 class 组件。react hooks 的出现,标示着 react中不会在存在无状态组件了,只有类组件和函数组件。具体可查看官网。 函数组件不能使用state,遇到交互更改状态等复杂逻辑时不能更好地支持,hooks让函数组件更靠近class组件,拥抱函数式编程。 解决副作⽤问题,hooks出现可以处理数据获取、订阅、定时执行任务、手动修 useReducer 是 useState 的替代品,它可以更好的管理组件的状态。 useReudcer 的格式: import { useReducer } from "react"; let [state, dispatch] = useReducer(reducer, initialArg, init); 各个变量的含义: state 拿到状态数据; dispatch 派发 action 的函数; reducer 我们自己编写的 reducer 函数; 在 React 中使用 Immer 管理不可变状态 在 React 中,使用不可变状态可以快速且高效地比较更改前后的状态树。因此,每个组件可在执行任何成本很高的 DOM 操作之前,决定是否重新渲染。 我希望你已经知道: javaScript 是可变的,我们必须自己实现不可变性。 像 Redux 这样流行的状态管理库也遵循着相同的理念。当我们使用 reducers(译者注:根级的 reduce 函数 reducer 拆分为多个 reducers)时,它期望我们不要改变状态,以避免产生任何的副作用。但是,对 不可变数据 React的老手们早就知道为什么要用不可变数据了,但是为了防止新手们看不懂,所以还是要解释一下什么是不可变数据,不可变数据指的其实就是当你修改一个数据的时候,这个数据会给你返回一个新的引用,而自己的引用保持不变,有点像是经常用到的数组的map方法: const arr1 = [1, 2, 3]; const arr2 = arr1.map(item => item * 10); 动手点关注干货不迷路useStateuseState 可以说是我们日常最常用的 hook 之一了,在实际使用过程中,有一些简单的小技巧能帮助你提升性能 & 减少出 bug 的概率。使用 惰性初始值(https://reactjs.org/docs/hooks-reference.html#lazy-initial-state)通常我们会使用以下的方式初始化 state。const[st... hook都是一些以use开头的函数,表示钩子React 官网提供了 些内置的 hook:ruseStateuseEffect、useMemo、useCallback…允许自定义 hookhook使用规则:只能用于函数组件函数组件中使用自定义hook中使用需要在函数组件的顶层调用,不能在if、for、嵌套中使用需要以use开头。 背景本文旨在分享,React hook 在中大型中台项目中的实践,适合熟悉 React hook 用法的同学,希望能对你有帮助。用到的库1. unstated-next200 bytes to never think about React state management libraries ever again.永远不必再考虑 React 状态管理了,仅仅 200 字节的状态管理解决...