当前位置: 首页 > news >正文

做网站必须会编程吗今日百度关键词排名

做网站必须会编程吗,今日百度关键词排名,台州网站设计 解放路,新乡网站制作在 react 开发中, useEffect 是我们经常会使用到的钩子,一个基础的例子如下: useEffect(() > {// some code here// cleanup 函数return () > {doSomething()} }, [dependencies])上述代码中, cleanup 函数的执行时机有如下…

在 react 开发中, useEffect 是我们经常会使用到的钩子,一个基础的例子如下:

useEffect(() => {// some code here// cleanup 函数return () => {doSomething()}
}, [dependencies])

上述代码中, cleanup 函数的执行时机有如下两种:

  • 组件卸载时会执行一次
  • 每个依赖项(dependencies)变更后,页面重新渲染前会执行一次

在日常的开发中,我们很多人都会忽略掉 cleanup 函数,在一般情况下,不写 cleanup 函数不会有什么问题。但如果我们在 useEffect中使用了定时器或者进行了网络请求,这种情况下,如果不在 cleanup 函数中执行一些清除逻辑,会导致一些潜在的 bug。下面来聊聊如何使用 cleanup 函数解决内存占用网络请求竞态问题.

不在 cleanup 函数中清除旧定时器会发生什么?

我们使用 interval 写一个计数器例子,count 从 0 开始,每秒递增 1,如下:

function Counter() {let [count, setCount] = useState(0)useEffect(() => {console.log('effect')setInterval(() => {setCount(count + 1)}, 1000)}, [count])return (<div><div>{count}</div></div>)
}

上述例子,一开始递增到前面几个数字,页面看起来是正常的,但是越往后,就会发现,数字在闪烁,而且之后页面会卡住,一段时间后的结果如下:
在这里插入图片描述
上图中,count 递增到 15 ,但 useEffect 却运行了 95 次,也就是,此时页面上已经有了 95 个定时器,越往后,定时器越多,为什么会这样?正常的结果应该是 count 增加到多少, useEffect 就运行多少次 (除了初始渲染运行的那一次),因为我们把 count 作为 useEffect 的依赖项。

导致上述问题的根本原因是我们没有清除旧的定时器,count 发生变化时,组件会重新渲染, useEffect 重新运行,会创建一个新的定时器,而旧的定时器并没有被清除,导致多个定时器同时存在,占用了更多的内存,这就是后续页面卡住的原因。

而页面上的数字闪烁的问题是因为每次组件重新渲染时,都会重新调用 useEffect,导致新的定时器开始运行,而旧的定时器还在继续工作。这样就会出现两个定时器交替执行的情况,导致数字的变化不稳定,造成闪烁的效果。

解决办法就是在 cleanup 函数中清除旧的定时器,代码如下:

function Counter() {// ...useEffect(() => {console.log('effect')const interval = setInterval(() => {setCount(count + 1)}, 1000)return () => {clearInterval(interval)}}, [count])// ...
}

清除旧的定时器之后,页面的表现就符合预期了,每次重新渲染,页面上有且只有一个定时器。

除了定时器这种场景,其他场景,如订阅、使用 IntersectionObserver 观察者,都需要注意在 cleanup 函数中执行对应的清除逻辑,以避免内存泄露问题。

cleanup 函数解决网络请求问题

case1:离开页面时请求未完成

一个在 useEffect 中进行网络请求例子如下:

function List() {const [lists,setLists] = useState([])useEffect(() => {fetch('https://jsonplaceholder.typicode.com/todos').then(res => res.json()).then(data => {alert('请求完成')setLists(data)})}, [])return (<div>{lists?.map((item) => (<p key={item.id}>{item.title}</p>))}</div>)
}export default List

上述代码是一个列表组件,通过 fetch 请求获取列表数据,最终渲染在页面上,这看起来没什么问题,我们平常就是这么写的。

我们增加一个 Home 组件,功能很简单,就是从 Home 页面跳转到上述的 List 页面,代码如下:

import { Link } from 'react-router-dom'function Home() {return (<div><Link to="/list">Go to lists</Link></div>)
}export default Home

我们从 Home 页面跳转到 List 页面,然后 List 页面开始请求 list 列表数据。跳到 List 页面后,在请求完成之前通过浏览器的回退按钮回到 Home 页面,交互过程如下:

浏览器后退按钮取消请求

视频中,我们把网络设置成弱网环境,在 List 页面的 fetch 请求还没完成,就回到了 Home 页面,我们期望 then 回调里的代码不应该执行,因为离开了 List 页面后,List 组件相当于销毁了,不应该再继续执行组件代码,然而结果却是执行了

造成上述结果的原因是:fetch 请求是异步的,进入 List 页面请时求已经发出,离开 List 页面没有取消请求,所以请求继续进行,完成后就会执行 then 回调里的代码

解决办法如下:

// ...
useEffect(() => {let isCancelled = falsefetch('https://jsonplaceholder.typicode.com/todos').then(res => res.json()).then(data => {if (!isCancelled) {alert('请求已完成')setLists(data)}})return () => {isCancelled = true}
}, [])
// ...

上述代码中,我们定义了一个标志位变量:isCancelled表示当前请求是否需要取消(这里并不是真正的取消请求,如何取消请求下文会讲到),初始化为 false,在 then 回调里,只有判断请求不需要取消才会执行后续代码。最后,重点来了,前面讲到 cleanup 函数的执行时机之一是在组件销毁时,所以在离开 List 页面时,我们把 isCancelled 设置为 true,那么后续请求完成时,就不会进入 if (!isCancelled) {} 条件语句中。

case2:同时触发多个相同请求,网络竞态问题

定义一个 User 组件,如下:

import { useState, useEffect } from "react";
import {useLocation,Link} from 'react-router-dom'function User() {const [curUser,setCurUser] = useState({})const route = useLocation()const id = route.pathname.split('/')[2]useEffect(() => {fetch(`https://jsonplaceholder.typicode.com/users/${id}`).then(res => res.json()).then(data => {setCurUser(data)})}, [id])return (<div style={{display: 'flex',flexDirection: 'column',alignItems: 'center'}}><p>name: {curUser.name}</p><p>username: {curUser.username}</p><p>email: {curUser.email}</p><Link to='/users/1'>fetch user 1</Link><Link to='/users/2'>fetch user 2</Link><Link to='/users/3'>fetch user 3</Link></div>)
}export default User

上述是一个获取用户信息并展示在页面上的例子,我们点击 Link 组件,更新路由中的用户 id,在 useEffect 中根据 id 去请求用户数据。在网络正常的情况下,我们快速切换用户 id,页面上的用户信息就会跟着改变,这看起来没什么问题。如果我们把网络设置成弱网环境,同样的操作结果如下:

网络请求竞态视频1

在上述视频中,当前用户是 user1,我们快速点击 fetch user2、fetch user3,并最终停留在 user3,正常情况下,最终页面展示的应该是 user3 的信息,但是实际结果是:先展示 user2 的信息,然后再展示 user3 的信息。

上述问题其实涉及到了网络竞态问题。网络竞态是用户触发同一个请求多次,由于网络的波动,每个请求的响应时间是不一样的,最先触发的请求可能是最后一个返回响应的,最后触发的请求也可能是最先返回响应的,最终所有请求完成后,我们应该使用哪个请求的响应作为最终的数据结果?。答案使用最后一个触发的请求的响应作为最终的结果,因为这是最新的,最具时效性的数据。

在上述 fetch user 的例子中,我们应该丢弃 fetch user2 的响应,因为我们最后操作的是 fetch user 3,页面最终应该展示的是 user3 的数据。我们同样使用 cleanup 函数来解决网络竞态问题,写法和 case1 类似,如下:

// ...
useEffect(() => {let isCancelled = falsefetch(`https://jsonplaceholder.typicode.com/users/${id}`).then(res => res.json()).then(data => {if (!isCancelled) {setCurUser(data)}})return () => {isCancelled = true}}, [id])
// ...

前面讲到, cleanup 函数的另一个执行时机是:每个依赖项变更后,页面重新渲染前运行一次,所以我们快速点击 fetch user2、fetch user3,id 从 2 到 3,那么id 为 2 时对应的 isCancelled 变量被设置为了 true,所以此时就不会进入 if (!isCancelled) {} 条件语句中执行 setCurUser(data),那么 id 为 2 的这条响应就被丢弃了,最终页面就不会先展示 user2 的信息再展示 user3 的信息。最终结果视频所示:

网络请求竞态视频2

拓展

前面我们讲了如何借助 cleanup 函数来丢弃响应,但可能很多时候,对于无效的请求,我们希望能取消它,对于 fetch 请求,我们借助 fetch 的第二个参数中 signal 和 AbortController 实现,如下:

// ...
useEffect(() => {let controller = new AbortController()let signal = controller.signalfetch(`https://jsonplaceholder.typicode.com/users/${id}`,{signal}).then(res => res.json()).then(data => {setCurUser(data)})return () => {// 在 cleanup 函数中终止当前请求controller.abort()}
}, [id])// ...

结果如下:

取消网络请求

在上述视频中,我们看到在点击 fetch user3 之后,fetch user2 的请求状态变成了已取消

在平时的开发中,我们一般会用 axios 进行请求,下面是 axios 取消请求的例子:

import axios from 'axios'
// ...
useEffect(() => {const CancelToken = axios.CancelTokenconst source = CancelToken.source()axios.get(`https://jsonplaceholder.typicode.com/users/${id}`,{cancelToken: source.token}).then(res => {setCurUser(res.data)})return () => {source.cancel()}
}, [id])// ...
http://www.hkea.cn/news/790528/

相关文章:

  • 免费做网站公司黑帽seo排名技术
  • apk连接wordpress上海seo
  • 企业建网站租用服务器好还是买一个好石家庄网站关键词推广
  • wordpress文件解析外贸网站优化
  • 建设工程竣工备案网站百度保障中心人工电话
  • 韶关城乡建设部网站首页营销型网站建设策划书
  • 建设银行手机银行下载官方网站谷歌浏览器网页版入口在哪里
  • 网站建设 好域名注册信息
  • 公众号微网站建设认证哪个推广网站好
  • 爬取1024上传到wordpress蔡甸seo排名公司
  • 流感吃什么药更好seo的方法
  • 营销型网站建设市场seo黑帽技术有哪些
  • 扬中做网站的公司seo虚拟外链
  • 永川集团网站建设免费网站seo诊断
  • 国外 上海网站建设网络营销推广方式案例
  • 24手表网站网络技术推广服务
  • 鞍山网站制作推广游戏推广员判几年
  • 360如何做网站优化网页设计制作软件
  • 金华网站建设电话电商运营主要负责什么
  • 百度的官方网站游戏推广工作好做吗
  • 著名的深圳网站建设网页快照
  • 政务网站建设要求快速排名软件哪个好
  • 自己网站怎么做优化色盲和色弱的区别
  • 苏州建网站公司seo网络推广培训班
  • 福清市建设局网站石家庄学院
  • 找考卷做要去哪个网站中国国家培训网官网查询
  • 软件系统开发的大概步骤优化网站标题名词解释
  • 院校网站建设模板建站平台
  • 淘宝网站内搜索引擎优化怎么做广告推广平台网站有哪些
  • 大片播放网站国外免费推广网站有哪些