React 函数组件中对window添加事件监听resize导致回调不能获得Hooks最新状态的问题解决思路
React 函数组件中对window添加事件监听resize导致回调不能获得Hooks最新状态的问题解决思路
这几天在忙着把自己做的项目中的类组件转化为功能相同的函数组件,首先先贴一份该组件类组件的关键代码:
import React, {Component} from "react"
// 防抖组件
import { debounce } from 'throttle-debounce';
// 引入connect用于连接UI组件与redux
import {connect} from "react-redux"
class HandSendMsg extends Component {
state = {
w_width:window.innerWidth,
w_height:window.innerHeight,
}
// 向UE4像素流发送消息
emitMessageToUE4 = (msgObj) => {
// this.props.video_ref证明已经挂载了UE4像素流推送标签组件
if(this.props.video_ref && this.props.video_ref.current && this.props.video_ref.current.emitMessage instanceof Function) {
this.props.video_ref.current.emitMessage(msgObj);
}
}
// 修改分辨率的函数回调
handleResize = () => {
let w_width = window.innerWidth
let w_height = window.innerHeight
this.setState({w_width, w_height})
this.emitMessageToUE4({
time:Date.now(),
width:w_width,
height:w_height,
funcName:"onResize"
})
}
componentDidMount() {
// 给全局绑定一个修改分辨率的操作, 当窗口发生变化的时候就修改分辨率,加入了防抖操作
window.addEventListener("resize", debounce(300, false, this.handleResize.bind(this)))
}
render() {
const {w_height, w_width, iconLocList } = this.state
return (
<div>
</div>
)
}
}
// 使用connect()()创建并暴露一个Count的容器组件
export default connect(
state => ({
signal_state:state.signal,
video_ref:state.videoRef
}),
{
}
)(HandSendMsg)
然后我试着改写成函数组件,初始关键代码是这样的:
import React, { useState, useEffect } from 'react'
// 防抖组件
import { debounce } from 'throttle-debounce';
// 引入useSelector用于读取redux store中保存的数据
import { useSelector } from "react-redux"
export default function HandSendMsg() {
// state数据
const [wh, setWh] = useState({
width:window.innerWidth,
height:window.innerHeight
})
// 标志是否开始监听UE4消息,确保只监听一次
const [start_listen, setStart_listen] = useState(false)
// store里保存的数据
const signal_state = useSelector(state => state.signal)
const video_ref = useSelector(state => state.videoRef)
// 向UE4像素流发送消息
const emitMessageToUE4 = (msgObj) => {
// video_ref不为null证明已经挂载了UE4像素流推送组件
if(video_ref && video_ref.current && video_ref.current.emitMessage instanceof Function) {
video_ref.current.emitMessage(msgObj);
}
}
// 修改分辨率的函数回调
function handleResize() {
let w_width = window.innerWidth
let w_height = window.innerHeight
emitMessageToUE4({
time:Date.now(),
width:w_width,
height:w_height,
funcName:"onResize"
})
setWh({
width:w_width,
height:w_height
})
}
useEffect(() => {
// 给全局绑定一个修改分辨率的操作, 当窗口发生变化的时候就修改分辨率
window.addEventListener('resize',debounce(300,false,handleResize))
// eslint-disable-next-line
}, [])
return (
<div>
</div>
)
}
useState钩子替代类组件中的state,useEffect副作用钩子替代类组件中的生命周期钩子(componentDidMount(), componentDidUpdate()和 componentWillUnmount()), useSelector和useDispatch来取代redux中的connect,这些都没什么好说的,但是在我给window添加onresize的事件监听的时候, 却发现只能获取到hooks的初始值,里面函数的调用根本无法获得最新的hooks值,无法更新state值:
window.addEventListener('resize',debounce(300,false,handleResize))
于是我在return里加了几个button,一个button用来获取最新的hooks的值,一个button用来调用window的onresize所调用的handleResize函数,发现在外面可以进行最新hooks的获取和更新,如下图所示:

在费劲周折之后,在网上看到帖子说可以对这个useEffect进行优化,使其监听一个变量,从而来使事件的绑定有效,我想了一下,要想使信息发送过去,我必须得确保signal_state这个值为true,那么我就用它来进行监听吧,当其从false改为true的时候再开启onResize的事件监听,问题不就解决了么。然后实践了一下,果然可以了,关键代码如下:
import React, { useState, useEffect } from 'react'
// 防抖组件
import { debounce } from 'throttle-debounce';
// 引入useSelector用于读取redux store中保存的数据
import { useSelector } from "react-redux"
export default function HandSendMsg() {
// state数据
const [wh, setWh] = useState({
width:window.innerWidth,
height:window.innerHeight
})
// 标志是否开始监听UE4消息,确保只监听一次
const [start_listen, setStart_listen] = useState(false)
// store里保存的数据
const signal_state = useSelector(state => state.signal)
const video_ref = useSelector(state => state.videoRef)
// 向UE4像素流发送消息
const emitMessageToUE4 = (msgObj) => {
// video_ref不为null证明已经挂载了UE4像素流推送组件
if(video_ref && video_ref.current && video_ref.current.emitMessage instanceof Function) {
video_ref.current.emitMessage(msgObj);
}
}
// 修改分辨率的函数回调
function handleResize() {
let w_width = window.innerWidth
let w_height = window.innerHeight
emitMessageToUE4({
time:Date.now(),
width:w_width,
height:w_height,
funcName:"onResize"
})
setWh({
width:w_width,
height:w_height
})
}
useEffect(() => {
// 给全局绑定一个修改分辨率的操作, 当窗口发生变化的时候就修改分辨率
// 只有signal_state即信令状态由false改为true的时候才添加一次事件
if(signal_state) {
window.addEventListener('resize',debounce(300,false,handleResize))
}
// eslint-disable-next-line
}, [signal_state])
return (
<div>
</div>
)
}
至此,问题已经解决了,总体来说函数式组件由于市面上教程较少,坑也比较多,这次这个给window添加监听事件的需要有一个变量同时监听变化,使得useEffect()可以正确响应然后重新绑定监听,为什么要使用useEffect()呢?因为我们的需求是必须确保只给window添加一次事件监听,当然得要求是对的了,而useEffect()可以模拟componentDidMount(), 可以最快的解决。
如果大家还有什么疑问或者新的建议,希望大家可以在下面留言,我看到一定会回复的,谢谢!!!
React 函数组件中对window添加事件监听resize导致回调不能获得Hooks最新状态的问题解决思路的更多相关文章
- vue中给window添加滚动监听无效的解决方案
原文链接: 点我 页面中有这么一个需求,当页面滚动到一定高度之后,页面中的某些元素进行吸顶,固定到顶部位置,或者是滚动到一定程度进行更新数据的操作.我相信不少网友查阅过类似的资料,网友给出的解决方案, ...
- js添加事件监听的方式与this
js添加事件监听与this js添加事件监听的方式与this 在标签中调用自定义函数 DOM0级事件处理程序 DOM2级事件处理程序 this 代表谁? js添加事件监听的方式与this <di ...
- GridView添加事件监听和常用属性解析
1. 使用流程 graph LR 准备数据源-->新建适配器 新建适配器-->绑定数据源 绑定数据源-->加载适配器 2. 常用属性 android:columnWidth:每一列的 ...
- extjs组件添加事件监听的三种方式
extjs对组件添加监听的三种方式 在定义组件的配置时设置 如代码中所示: Java代码 xtype : 'textarea', name : 'dataSetField', labelSe ...
- vuejs2.0实现分页组件,使用$emit进行事件监听数据传递
上一篇文章介绍了vuejs实现的简单分页,如果我有几个页面都需要有分页效果,不可能每个页面都去复制一下这段代码吧,意思是封装一下,变成通用的组件. 首先使用基础 Vue 构造器,创建一个“子类”,Vu ...
- [转]extjs组件添加事件监听的三种方式
原文地址:http://blog.csdn.net/y6300023290/article/details/18989635 1.在定义组件配置的时候设置 xtype : 'textarea', na ...
- Android实战简易教程-第十五枪(实现ListView中Button点击事件监听)
1.main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" x ...
- 添加事件监听兼容IE6-8
IE8一下浏览器不支持addEventListener,用attachEvent取而代之,但是在时间类型前面要加上’on‘,例如click时间在attachEvent中要写成onclick. var ...
- 使用addeventlistener为js动态创建的元素添加事件监听
点击li弹出内容,并且动态添加li之后有效 <button onclick="addFunction()">点我增加</button> <ul> ...
随机推荐
- 【刷题-LeetCode】236. Lowest Common Ancestor of a Binary Tree
Lowest Common Ancestor of a Binary Tree Given a binary tree, find the lowest common ancestor (LCA) o ...
- 【记录一个问题】opencv中 cv::dft()与cv::ocl_dft()计算的结果相差较大
以一个跟踪算法来测试: 使用cv::dft(), 矩阵未按照2次幂对齐,最终跟踪平均准确率 84.3% 使用cv::dft(),矩阵使用cv::copyMakeBorder对齐,最终跟踪平均准确率 8 ...
- WebGPU图形编程(3):构建三角形图元<学习引自徐博士教程>
一.首先修改你的index.html文件 请注意主要在html页面修改添加的是需要加选择项:"triangle-list"和"triangle-strip",如 ...
- python18day
今日内容 ''' 用代码模拟博客园系统. 项目分析: 一.首先程序启动,页面显示下面内容供用户选择: 1.请登录 2.请注册 3.进入文章页面 4.进入评论页面 5.进入日记页面 6.进入收藏页面 7 ...
- 泛型编程与 OI——modint
博客链接. 在 OI 中,有大量的题目要求对一些数字取模,这便是本文写作的背景. 背景介绍 这些题目要么是因为答案太大,不方便输出结果,例如许多计数 dp:要么是因为答案是浮点数,出题人不愿意写一个确 ...
- SpringBoot 简单介绍
一.springboot是啥? 1.什么是springboot? 1.1springboot是spring生态圈的一个轻量级框架,换句话说springboot就是spring,是spring的一个衍生 ...
- Linux 常见文件管理命令
Linux文件系统 根目录:/ 从根目录开始,下面有一堆小目录 root:根用户的目录 bin:可执行文件命令 etc:配置文件 var:日志 lib:安装包或头文件,库文件 home:所有用户的家目 ...
- ApacheCN 大数据译文集(二) 20211206 更新
Hadoop3 大数据分析 零.前言 一.Hadoop 简介 二.大数据分析概述 三.MapReduce 大数据处理 四.基于 Python 和 Hadoop 的科学计算和大数据分析 五.基于 R 和 ...
- PyTorch 介绍 | AUTOMATIC DIFFERENTIATION WITH TORCH.AUTOGRAD
训练神经网络时,最常用的算法就是反向传播.在该算法中,参数(模型权重)会根据损失函数关于对应参数的梯度进行调整. 为了计算这些梯度,PyTorch内置了名为 torch.autograd 的微分引擎. ...
- Gitee 自已提交的代码提交人头像为他人、码云上独自开发的项目显示为 2 个开发者
简介 自己写的代码提交到码云(Gitee)上却变成了两个人,一个被正确的代码提交统计了,另一个却没有,并且确信自己输入的Gitee账号是自己绑定的邮箱,具体如下: 解决办法 查看自己的用户名 git ...