Hi,丹尼尔,今天咱们来聊一聊 "如何安全地使用 state" 怎么样?react
丹尼尔:安全?难道使用 React Hooks 的 state 还会带来危险?X﹏X 紧张~
放松放松,关于安全,等会我给个例子就会很好理解了。没有例子的辅助,好难一会儿说明白,也多是个人表达能力 So So 吧!git
丹尼尔:好吧。在场的各位同窗,有不清楚 React Hooks 是什么的吗?
也许有一些同窗还不太了解,我就简单地介绍下(忽然有种凑字数的嫌疑 ヘ(・_|):github
React Hooks 是个好东西,它让你能够用纯函数来实现有状态的组件,今后你不用再纠结组件究竟是有状态仍是无状态,从而在纯函数和类两种实现间徘徊(固然好处多多,毫不止这个,后面我会专门写一篇介绍 Why React Hooks 的文章滴😬)。数组
一旦你踏上 React Hooks 的征途,就会碰到各类各样奇怪的问题。安全
这很正常,一个新事物的诞生,老是伴随着各类问题,而后在打怪中不断升级成长,最终成为。。。函数
丹尼尔:喂喂,别扯远了
🤪若是你有看过关于 React Hooks 的官方文档,看过里面的一些例子,你可能会以为,挺简单的,不过是改为用 useState
来使用 state 而已,没啥难度。this
然而就在你放松警戒的这个moment,“危险”正在悄悄地在某些角落降临了。spa
丹尼尔:紧张,什么危险,不会失身吧
😅 额~~3d
对于 state 值的获取,你可能取到了一个不是你所指望的旧值,即不是最新的状态值。code
你须要时时刻刻保持清醒,才有可能绕过这些“危险”。
丹尼尔:😵
看着你一脸蒙B的样子,我这就赶忙给个例子哈。
栗子来了:当你在表单上填写了一些信息,而后离开表单时,但愿能自动保存为草稿,以便下次进来时能还原,省去从新填写的麻烦。
下面给出简化版的实现:
import React, { useState, useEffect } from "react"; export const UseStateDemoComp1 = () => { const [name, setName] = useState('daniel'); useEffect(function() { return () => { saveDraft() } }, []) function saveDraft() { console.log('Save Draft:', name); } return ( <div> <form> <input value={name} onChange={e => setName(e.target.value)}></input> </form> </div> ); };
昨一看,代码好像没啥问题。
传给 useEffect
的 function 返回了一个 function,该 function 至关于原来的componentWillUnmount
生命周期方法,即只在组件快销毁的时候才会调用执行。在该方法里面执行一些逻辑,这里调用saveDraft
方法,获取 name state 的值,而后保存。
找出问题了吗?若是没有,那咱们直接看个动图吧,看看问题所在:
点击 Toggle 按钮会销毁掉组件,因此会触发销毁动做。从动图能够看到,咱们填写的是“sarah”,但在销毁执行的方法中,取到的值倒是“daniel”
丹尼尔:这是为何呢?不该该是最新的值吗?😶
由于useEffect
的依赖是个空数组,因此在整个组件生命周期只会执行一次,即在组件第一次完成渲染后执行,而useEffect
的方法里面用到的 state 值就是当时最新的state值,能够用快照来理解。在接下来的时间里,不管组件从新渲染多少次,都不会改变里面的 state 的值,由于它只是当时的快照
有同窗可能会说,把 name 加进 useEffect
依赖的数组里面就好了。以下:
useEffect(function() { return () => { saveDraft() } }, [name])
看上去好像是知足了需求,但依然有问题。由于我只想在组件退出的时候才保存,但如今的效果就是表单字段值一旦改变,就会保存,保存操做变得很是的频繁。
丹尼尔:因此你想说 React Hooks 对此毫无办法?
固然不是啦,经过 useRef
和 useEffect
是能够实现上面的需求的。怎么实现?同窗们就本身动下脑筋吧。当你实现出来后,你会发现代码不只啰嗦,可读性还差。
丹尼尔:好了,请开始你的表演吧
😎有了上面的例子,这里就能够对安全地使用state
做个描述了:
“安全地使用 state,就是不管你在什么时候何地以何种方式读取 state 的值时,它老是符合你的预期,老是最新的那个值,而不用你当心翼翼地去判断它会不会是个没更新的旧值”
官方提供了自定义Hooks的能力,就是想经过社区的共同努力,来持续完善Hooks。
接下来咱们经过 【nice-hooks】这个第三方自定义Hooks的开源项目,使用它的 useSingleState
来代替 useState,话很少说,直接上代码
import React, { useEffect } from "react"; import { useSingleState } from "nice-hooks"; export const DemoComp1 = () => { const [state, setState] = useSingleState({ name: 'daniel' }); useEffect(function() { return () => { saveDraft() } }, []) function saveDraft() { console.log('Save Draft:', state.name); } return ( <div> <form> <input value={state.name} onChange={e => setState({name: e.target.value})}></input> </form> </div> ); };
先来个动图直接看下效果。完美~
这里介绍一下useSingleState
这个 hook:它使用相似于 class
形式的 this.state
和 this.setState
的方式来使用 state,因此很是容易上手。最重要是它能够安全地
使用 state,而且拥有 callback
能力。
最后咱们使用 useLifeCycle
这个 hook 对代码进一步完善。好了,下面的代码成品相比于直接使用官方的 hooks,是否是感受好多了。
import React from "react"; import { useSingleState, useLifeCycle } from "nice-hooks"; export const DemoComp1 = () => { const [state, setState] = useSingleState({ name: 'daniel' }); useLifeCycle({ willUnmount() { saveDraft() } }) function saveDraft() { console.log('Save Draft:', state.name); } return ( <div> <form> <input value={state.name} onChange={e => setState({name: e.target.value})}></input> </form> </div> ); };
时间真快,又到了该说再见的时候。
若是你以为这篇文章写得还能够,还请点个赞哦。
若是你以为 nice-hooks 还不错,还请加颗☆哦。
ByeBye!
Keywords: react, hooks, nice-hooks