您现在的位置是:网站首页> 编程资料编程资料
react中的watch监视属性-useEffect介绍_React_
2023-05-24
232人已围观
简介 react中的watch监视属性-useEffect介绍_React_
react的watch监视属性-useEffect
在vue中可以使用watch属性,去监视一个值,当这个值进行变化的时候就去执行一些操作。在react是没有这个属性的,但是它也一样可以达到相同的效果,那么接下来看看它是怎么实现的呢?
在react中实现监听效果有一个比较简单的方法,就是使用useEffect 这个hook,在我们刚接触这个hook时经常会被代入到类组件中的生命周期上,其实它不光有生命周期的功能更是可以实现监听的效果。
1、首先我们先来看下useEffect 用来当作生命周期时是怎么使用的,代码如下:
import React, { useEffect, useState } from 'react' export default function Wtach() { const [num, setNum] = useState(0) useEffect(() => { console.log('我是初始化的hook') return () => { console.log('我是卸载的hook') } }, []) useEffect(() => { console.log('我是更新的hook') }) return ( {`当前数量是${num}`}
) } 上述代码中,第一个useEffect 中传入两个参数第一个参数为一个callback回调函数, 第二个参数传入一个空数组,callback回调函数又返回了一个用于卸载组件时调用的函数。
他们的调用时期分别为初始化加载完成页面调用useEffect 传入的第一个函数(此时对应omponentDidMount生命周期钩子),在卸载的时候react会调用第一个callback函数里面返回的函数(此时对应componentWillUnmount生命周期钩子),这样以来他们就完全实现了和生命周期一样的两个功能。
打印如下:

再来看第二个useEffect ,它只传入了一个callback回调参数,这个传入的callback就会在每次页面更新完成后进行调用(它对应了componentDidUpdate生命周期钩子)。
效果如下:

2、上面看完了useEffect 实现生命周期的功能,下面就来看下它是怎么实现类似watch属性的。
代码如下:
import React, { useEffect, useState } from 'react' export default function Wtach() { const [num, setNum] = useState(0) useEffect(() => { console.log('我是改变后的num', num) }, [num]) return ( {`当前数量是${num}`}
) } 上述代码useEffect 中除了正常传入第一个callback函数,第二个参数传入一个数组里面的值是num,此时传入的callback函数的调用就依赖了第二个参数数组中num的值,每当num的值改变后react就会去调用传入的第一个callback函数,这样就实现了类似watch属性的功能。
效果如下:

最后如果你想要监听多个值,不需要写多个useEffect ,只需要在第二个数组参数中增加新的值即可,如下:

useEffect使用指南
最近在写一些React的应用,用上了最新的Hooks。Hooks好用,但是对于刚上手Hooks的小伙伴来说,坑也挺多的。所以决定总结一下Hooks的使用经验,从useEffect开始。useEffect用于处理组件中的effect,通常用于请求数据,事件处理,订阅等相关操作。这里以数据请求为例,来深入介绍useEffect的用法。
最基本的使用
首先,举一个简单的例子:
import React, { useState } from 'react'; function App() { const [data, setData] = useState({ hits: [] }); return ( - {data.hits.map(item => (
- {item.title} ))}
App组件显示了一个项目列表,状态和状态更新函数来自与useState这个hooks,通过调用useState,来创建App组件的内部状态。初始状态是一个object,其中的hits为一个空数组,目前还没有请求后端的接口。
为了获取后端提供的数据,接下来将使用axios来发起请求,同样也可以使用fetch,这里会使用useEffect来隔离副作用。
import React, { useState, useEffect } from 'react'; import axios from 'axios'; function App() { const [data, setData] = useState({ hits: [] }); useEffect(async () => { const result = await axios( 'http://localhost/api/v1/search?query=redux', ); setData(result.data); }); return ( - {data.hits.map(item => (
- {item.title} ))}
在useEffect中,不仅会请求后端的数据,还会通过调用setData来更新本地的状态,这样会触发view的更新。
但是,运行这个程序的时候,会出现无限循环的情况。useEffect在组件mount时执行,但也会在组件更新时执行。因为我们在每次请求数据之后都会设置本地的状态,所以组件会更新,因此useEffect会再次执行,因此出现了无限循环的情况。我们只想在组件mount时请求数据。我们可以传递一个空数组作为useEffect的第二个参数,这样就能避免在组件更新执行useEffect,只会在组件mount时执行。
import React, { useState, useEffect } from 'react'; import axios from 'axios'; function App() { const [data, setData] = useState({ hits: [] }); useEffect(async () => { const result = await axios( 'http://localhost/api/v1/search?query=redux', ); setData(result.data); }, []); return ( - {data.hits.map(item => (
- {item.title} ))}
useEffect的第二个参数可用于定义其依赖的所有变量。如果其中一个变量发生变化,则useEffect会再次运行。如果包含变量的数组为空,则在更新组件时useEffect不会再执行,因为它不会监听任何变量的变更。
还有最后一个问题。在代码中,我们使用async / await从第三方API获取数据。如果你对async/await熟悉的话,你会知道,每个async函数都会默认返回一个隐式的promise。但是,useEffect不应该返回任何内容。这就是为什么会在控制台日志中看到以下警告:
Warning: useEffect function must return a cleanup function or nothing. Promises and useEffect(async () => …) are not supported, but you can call an async function inside an effect
这就是为什么不能直接在useEffect中使用async函数,因此,我们可以不直接调用async函数,而是像下面这样:
import React, { useState, useEffect } from 'react'; import axios from 'axios'; function App() { const [data, setData] = useState({ hits: [] }); useEffect(() => { const fetchData = async () => { const result = await axios( 'http://localhost/api/v1/search?query=redux', ); setData(result.data); }; fetchData(); }, []); return ( - {data.hits.map(item => (
- {item.title} ))}
响应更新
上面的例子中,我们实现了再组件mount时请求数据。但是很多情况下,我们需要响应用户的输入,然后再请求。这个时候我们会引入一个input框,监听query值的变化:
import axios from 'axios'; function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); useEffect(() => { const fetchData = async () => { const result = await axios( 'http://localhost/api/v1/search?query=redux', ); setData(result.data); }; fetchData(); }, []); return ( setQuery(event.target.value)} /> {data.hits.map(item => ( - {item.title}
))}
); } export default App;有个query值,已经更新query的逻辑,还需要将这个query值传递给后台,这个操作会在useEffect中进行:
function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); useEffect(() => { const fetchData = async () => { const result = await axios( `http://localhost/api/v1/search?query=${query}`, ); setData(result.data); }; fetchData(); }, []); return ( ... ); } export default App;前面我们说了,目前的useEffect只会在组件mount时执行,并且useEffect的第二个参数是依赖的变量,一旦这个依赖的变量变动,useEffect就会重新执行,所以我们需要添加query为useEffect的依赖:
function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); useEffect(() => { const fetchData = async () => { const result = await axios( `http://localhost/api/v1/search?query=${query}`, ); setData(result.data); }; fetchData(); }, [query]); return ( ... ); } export default App;一旦更改了query值,就可以重新获取数据。但这会带来另一个问题:query的任何一次变动都会请求后端,这样会带来比较大的访问压力。这个时候我们需要引入一个按钮,点击这个按钮再发起请求
function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); const [search, setSearch] = useState(''); useEffect(() => { const fetchData = async () => { const result = await axios( `http://localhost/api/v1/search?query=${query}`, ); setData(result.data); }; fetchData(); }, [query]); return ( setQuery(event.target.value)} /> {data.hits.map(item => ( - {item.title}
))}
); }可以看到上面我们添加了一个新的按钮,然后创建新的组件state:search。每次点击按钮时,会把search的值设置为query,这个时候我们需要修改useEffect中的依赖项为search,这样每次点击按钮,search值变更,useEffect就会重新执行,避免不必要的变更:
function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); const [search, setSearch] = useState('redux'); useEffect(() => { const fetchData = async () => { const result = await axios( `http://localhost/api/v1/search?query=${search}`, ); setData(result.data); }; fetchData(); }, [search]); return ( ... ); } export default App;此外,search state的初始状态设置为与query state 相同的状态,因为组件首先会在mount时获取数据。所以简单点,直接将的要请求的后端URL设置为search state的初始值。
function App() { const [data, setData] = useState({ hi
相关内容
- vue自定义翻页组件的方法_vue.js_
- 使用useEffect模拟组件生命周期_React_
- 详解vue的Des加密解密_vue.js_
- solid.js响应式createSignal 源码解析_vue.js_
- 微信小程序全局数据共享和分包图文详解_javascript技巧_
- uniapp小程序配置tabbar底部导航栏实战指南_javascript技巧_
- Vue qiankun微前端实现详解_vue.js_
- JavaScript TypeScript实现贪吃蛇游戏完整详细流程_javascript技巧_
- 关于element ui中el-cascader的使用方式_vue.js_
- vue解析指令compile源码层面使用解析_vue.js_
点击排行
本栏推荐
