React函数式组件值之useEffect()
Effect Hook 可以让你在函数组件中执行副作用操作,这里提到副作用,什么是副作用呢,就是除了状态相关的逻辑,比如网络请求,监听事件,查找 dom。
可以这样说,在使用了useState或是useEffect这样的hooks之后,每次组件在render的时候都生成了一份本次render的state、function、effects,这些与之前或是之后的render里面的内容都是没有关系的。而对于class component来说,state是一种引用的形式。这就造成了二者在一些表现上的不同。
一、基础用法
定义一个函数和一个数组。函数体为组件初始化或变化时执行的代码,返回值为组件销毁前执行的代码。数组参数中放的是触发此函数的依赖项数据。
1 useEffect(() => {
2 // 相当于 componentDidMount、componentDidUpdate
3 console.log("code");
4 return () => {
5 // 相当于 componentWillUnmount
6 console.log("code");
7 }
8 }, [/*依赖项*/])
二、监听参数
类组件在绑定事件、解绑事件、设定定时器、查找 dom 的时候,是通过 componentDidMount、componentDidUpdate、componentWillUnmount 生命周期来实现的,而 useEffect 会在组件每次 render 之后调用,就相当于这三个生命周期函数,只不过可以通过传参来决定是否调用。
其中注意的是,useEffect 会返回一个回调函数,作用于清除上一次副作用遗留下来的状态,如果该 useEffect 只调用一次,该回调函数相当于 componentWillUnmount 生命周期。
决定useEffect中各部分代码角色的是第二个参数:
- 什么都不传,组件每次 render 之后 useEffect 都会调用,相当于 componentDidMount 和 componentDidUpdate
- 传入一个空数组 [], 只会调用一次,相当于 componentDidMount 和 componentWillUnmount
- 传入一个数组,其中包括变量,只有这些变量变动时,useEffect 才会执行
1 function App () {
2 const [ count, setCount ] = useState(0)
3 const [ width, setWidth ] = useState(document.body.clientWidth)
4 const onChange = () => {
5 setWidth(document.body.clientWidth)
6 }
7 //最简单用法
8 useEffect(() => {
9 //只有方法体,相当于componentDidMount和componentDidUpdate中的代码
10 document.title = count;
11 })
12 //加返回值用法
13 useEffect(() => {
14 //添加监听事件,相当于componentDidMount和componentDidUpdate中的代码
15 window.addEventListener('resize', onChange, false);
16 //返回的函数用于解绑事件,相当于componentWillUnmount中的代码
17 return () => {
18 window.removeEventListener('resize', onChange, false)
19 }
20 })
21 //加空数组参数用法
22 useEffect(() => {
23 // 相当于 componentDidMount
24 window.addEventListener('resize', onChange, false)
25 return () => {
26 // 相当于 componentWillUnmount
27 window.removeEventListener('resize', onChange, false)
28 }
29 }, []);
30 //加监听值用法
31 useEffect(() => {
32 //只有当count的值发生变化,此函数才会执行
33 console.log(`count change: count is ${count}`)
34 }, [ count ]);
35 return (
36 <div>
37 页面名称: { count }
38 页面宽度: { width }
39 <button onClick={() => { setCount(count + 1)}}>点我</button>
40 </div>
41 )
42 }
其实Function Component 不存在生命周期,把 Class Component 的生命周期概念搬过来试图对号入座只是一种辅助记忆手段,Function Component 仅描述 UI 状态,React 会将其同步到 DOM,仅此而已。
三、使用优化
我们在使用useState的时候,经常碰到capture value的问题,比如下面代码会输出5而不是3:
1 const App = () => {
2 const [temp, setTemp] = React.useState(5);
3 const printTime = () => {
4 setTimeout(() => console.log(temp), 3000);
5 };
6 return (
7 <div onClick={() => {
8 printTime();
9 setTemp(3);
10 }}
11 >clickMe</div>
12 );
13 };
在printTime函数执行的那个 Render 过程里,temp 的值可以看作常量 5,执行 setTemp(3) 时会交由一个全新的 Render 渲染,所以不会执行printTime函数。而 3 秒后执行的内容是由 temp 为 5 的那个 Render 发出的,所以结果自然为 5。
原因就是 temp、printTime 都拥有 Capture Value 特性。而useEffect 也一样具有 Capture Value 的特性。
利用 useRef 就可以绕过 Capture Value 的特性。可以认为 ref 在所有 Render 过程中保持着唯一引用,因此所有对 ref 的赋值或取值,拿到的都只有一个最终状态,而不会在每个 Render 间存在隔离。也可以简洁的认为,ref 是 Mutable 的,而 state 是 Immutable 的。
1 function Example() {
2 const [count, setCount] = useState(0);
3 const latestCount = useRef(count);
4 useEffect(() => {
5 //设置最新变量的引用
6 latestCount.current = count;
7 setTimeout(() => {
8 //读取引用指向的最新值
9 console.log(`You clicked ${latestCount.current} times`);
10 }, 3000);
11 });
12 return (
13 <div>
14 <p>You clicked {count} times</p>
15 <button onClick={() => setCount(count + 1)}>Click me</button>
16 </div>
17 );
18 }
相关文章
- 项目中遇到的问题:关系图组件兼容性问题解决
- 第二百节,jQuery EasyUI,Tabs(选项卡)组件
- react的3种组件
- [React Intl] Format Numbers with Separators and Currency Symbols using react-intl FormattedNumber
- [React Intl] Install and Configure the Entry Point of react-intl
- android 编程时,如何在Eclipse中查看Android源码或者第三方组件包源码
- react 组件生命周期
- [React Intl] Install and Configure the Entry Point of react-intl
- [React] Create an Auto Resizing Virtualized List with react-virtualized
- React的source code init时会自动检测Chrome dev tool的react extension装了没
- vs2010 com组件中没有 AxWMPLib与WMPLib
- 使用微搭自定义组件实现搜索组件
- 第52篇 QML自定义组件 — 组件化图片文字组合按钮
- React组件方法中为什么要绑定this
- React学习笔记(四)—— 组件通信与状态管理、Hooks、Redux、Mobx
- kettle的应用组件 、流程组件、查询组件、连接组件、统计组件、映射组件、脚本组件
- 无法卸载windows组件?提示zClientm.exe
- 【python自动化篇】jmeter组件介绍
- 小程序中使用weui组件库(一)
- Springboot+百度的WebUploader组件实现普通文件的批量上传
- Java Swing JRadioButton:单选按钮组件
- Android 组件化实施流程
- Taro React组件开发(8) —— RuiUploadImages 多图片上传组件【Promise.all 实现】
- Taro React组件使用(5) —— RuiPasswordInput 密码输入框显示隐藏和清空
- Taro React组件使用(4) —— RuiInputCode 验证码输入框
- Taro React组件开发(3) —— RuiRate 评论评分
- Taro React组件开发(2) —— RuiEditor 富文本编辑器【兼容H5和微信小程序】
- kubernetes组件_Service_普通Service和无头Service
- wine手动安装wine-mono和wine-gecko组件