阅读 3359

来自《React Hooks 与 Immutable》小册作者'神三元'的灵魂拷问

事情经过

事情的经过是这样:大家最近可能经常会见到掘金上有个广告👇

然后我看了评价感觉好像挺不错的,就买了(反正也不贵),加群了以后感觉作者很用心,不过最近项目一直在用Vue做PC端,就没怎么看这个小册,寻思忙完这段时间,过年的时候看。
但是就在这时我突然注意到了三元老师在推荐immer以后就有好多人在问immer是啥?

心血来潮的我决定是时候要给大家好好科普一下了,这么好用的东西应该尽快让大家都上手啊,不然作者心灰意冷了不继续维护了怎么办?于是我写了一篇文章:2020要用immer来代替immutable优化你的React项目
然后我发到了群里,并@了三元老师:

正当我暗自得意的时候他突然给我来了个灵魂拷问:

他问了我一个问题我没有回答上来:useImmer有什么优势?(因为我的那篇文章里写了用useImmer代替useState)👇

写文章的时候是参考的useImmer官方文档,这个文档是这么写的:

翻译:useImmer(initialState)和useState非常相似,这个方法返回一个数组,数组中第一个值是当前的state,第二个值是一个更新函数,更新函数接受一个函数来作为参数,这个函数的参数可以非常自由的去更改,当函数执行完之后将会生成一个不可变数据作为新的state

当时我并没有仔细的看这句话,注意力都集中在他文档的那个小案例上了,没有深入的去思考,结果被三元老师一语中的点醒了我:useImmer和useState相比它的优势到底在哪?

前两天一直在加班忙项目,甚至连2020年的第一天都在加班-.-! 也没时间去想这些,今天忙完了突然想起这件事,于是又去仔细看了一眼,终于明白了它比useState好在哪!

更加便捷的存储及修改state数据

Hooks上市之前我们是这么定义state的:

state = {
    people: [
      {
        name: '马云',
        englishName: 'Jack Ma'
      },
      {
        name: '马化腾',
        englishName: 'Pony Ma'
      },
      {
        name: '李彦宏',
        englishName: 'Robin Li'
      }
    ]
}
复制代码

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

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

其实这么写并不好,因为修改了参数 state 的 people 数组里面的值,相当于把这个引用里面的数据给改了,不符合 React 的 immutable 思想。

函数式setState写法要求每次都返回一个新的引用,不过自从有了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
来看看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可以让你直接修改state,看似不符合 immutable 的思想,但其实只是语法这么写,实际上并没有直接修改state的值,而是给你返回了一个全新的引用,并且比 immutable.js 更加高效。
毕竟内部是用了 Proxy 进行比对(有点像是把 Vue 的那一套搬过来了)

当然还有一个需要注意的地方:

原生的setState直接可以当作返回值,而这个useImmer生成的盗版useState修改后的值不能被直接当作返回值返回,所以需要在函数体外面有大括号。

当然也可以自定义返回值,返回什么值就会更新成什么值。

更具体的用法可以参照:2020要用immer来代替immutable优化你的React项目

手动@神三元

写到这里已经接近尾声了,这次写完了我要继续发群里@三元老师,看看这次他还会不会觉得useImmer这个钩子函数没有卵用了(点赞多的话后续我会继续更新文章发三元老师对话的截图)顺便免费给三元先生打个广告:React Hooks 与 Immutable 数据流实战

行了不扯淡了,喜欢我文章的朋友记得点关注!

后续

三元老师在这里道出了useImmer的使用场景,如果大家的业务场景与三元老师所说的用hooks代替redux场景类似,就可以在项目中试试这个神奇的hook!

往期精彩文章