如果我在延迟后执行清理活动会影响我的工作吗?

问题描述 投票:0回答:1

受此post的启发,如果我们在延迟后在清理中删除事件侦听器,事件处理程序的先前引用是否仍会附加到浏览器?

这是代码:

import React from "react";
import "./style.css";
// import React from "react";
// import "./style.css";
import { useState, useEffect,useRef } from 'react';

export default function App() {
  const [userText, setUserText] = useState('');
// Any event handler (function in JS) declared with (){} will be a new
// object in every render. So for every render hanleUserKeyPress is assigned a 
// new reference
  const handleUserKeyPress = event => {
    const { key, keyCode } = event;
    if (keyCode === 32 || (keyCode >= 65 && keyCode <= 90)) {
      // When this function is added as event listener to any browser activity
      // The entire code gets snapshotted i.e for every activity userText would
      // remain same.
      // For any browser activity added to this tag it will see :
      // const handleUserKeyPress = event => {
      //   const { key, keyCode } = event;
      //   if (keyCode === 32 || (keyCode >= 65 && keyCode <= 90)) {
      //     console.log('Value of userText : ' + '')//Added as snapshot
      //     console.log('Value of userText + key : ' + ''+key)
      //     setUserText(''+key);
      //   }
      // };

      console.log('Value of userText : ' + userText)
      console.log('Value of userText + key : ' + userText+key)
      setUserText(userText+key);
    }
  };


// This runs on every render(no dependency declared). 
  useEffect(() => {
    window.addEventListener('keydown', handleUserKeyPress);
    return () => {
      // Add a delay to see 
      async function fun(){
        await delay();
        window.removeEventListener('keydown', handleUserKeyPress);
      }
      fun();
    };
  });

  return (
    <div>
      <h1>Feel free to type!</h1>
      <blockquote>{userText}</blockquote>
    </div>
  );
}
function delay(){
  return new Promise(resolve =>{
    setTimeout(()=> resolve(),5000)
  })
}

因此,当安装程序最初运行时,React 会在handleUserKeyPress 中拍摄 userText 状态的快照,并将其添加到 keydown 事件中。

当按下某个键(假设为“k”)时,将调用 setUserText,因此组件的渲染将以值(“+”k”=“k”)进行。将代码提交到浏览器 DOM 后,应该运行清理操作。但在这里,我提供了 5 秒的延迟。在此期间,如果我按任意键,先前版本的事件处理程序仍会添加到 keydown 事件中。因此,在 5 秒结束之前按下的任何键(假设“m”)都会触发 handleUserKeyPress 函数,其中 userText 为“”,因此控制台应该打印“m”而不是“km”。另外 userText 应设置为“m”而不是“km”。

我哪里理解错了?

javascript reactjs react-hooks
1个回答
0
投票

您的代码每次组件渲染时都会创建一个新的“按键”事件侦听器,并且由于您延迟删除现有侦听器,这意味着在任何给定时刻都可以有超过 1 个按键事件侦听器处于活动状态并侦听。

在此期间,如果我按任意键,以前版本的 事件处理程序仍然添加到 keydown 事件中。因此任何 在 5 秒结束之前按下的键(假设为“m”)将 使用
handleUserKeyPress

作为

userText
触发
''
函数,因此 控制台应该打印
'm'
而不是
'km'
。另外
userText
应设置为
'm'
而不是
'km'

这是我认为您应该看到的确切行为,但我认为您误解了控制台日志。以下是一些带注释的日志输出示例:

log output

活动按下“k”"" + "k"5秒内按下“m” 按下“m”,按键侦听器 #1 控制台记录输出 -> 每个状态更新都会覆盖之前的状态,因此您会错过
描述
组件安装并创建按键侦听器#1
“k”被按下,按键侦听器 #1 控制台记录输出 ->
"k"
userText
状态更新排队到
"k"
,调用
useEffect
挂钩清理函数并将超时排队,组件重新渲染,并且按键侦听器 #2 在闭包中添加了
"k"

"" + "m""m"
userText
 状态更新排队到 
"m"
,按键侦听器 #2 控制台记录输出 
"k" + "m"
 -> 
"km"
userText
状态更新排队到
"km"
,调用
useEffect
钩子清理函数并将超时排队,组件重新渲染,并添加按键侦听器#3

"m"
的“中间”状态值,因为它会立即被

"km"

 覆盖,并且组件会使用当前状态值重新渲染。
	

© www.soinside.com 2019 - 2024. All rights reserved.