首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >React onSetstate函数被多次调用

React onSetstate函数被多次调用
EN

Stack Overflow用户
提问于 2021-10-08 10:11:03
回答 1查看 35关注 0票数 0

嗨,我在React中有这个组件,这个组件的作用是当输入字段值改变时,我将该值存储在messageIput state variable中,当用户开始键入时,我调用handleMessagePressprinting composing,并等待5秒,如果用户在5分钟后仍然键入,则再次输入printing composing,如果用户停止键入,则调用handleChangeprints paused。但是现在的问题是,当我在messageIput state variable中设置这个值的时候,它会再次打印合成。我想知道下面的代码片段是如何工作的,我想在我的react组件中这样做

代码语言:javascript
运行
复制
const { useRef, useState } = React;
const DEBOUNCE_THRESHOLD = 5000;
function App() {
  const [messageInput, setMessageInput] = useState("");
  const timeoutHandler = useRef(null);
  let executeHandlePress = true;
  const handleChange = (event) => {
    if (timeoutHandler.current) {
      clearTimeout(timeoutHandler.current);
    }
    timeoutHandler.current = setTimeout(() => {
      console.log("paused");
    }, DEBOUNCE_THRESHOLD);
  };
  const handleMessagePress = (e) => {
    if (!executeHandlePress) {
      // if flag false, return
      return;
    } else {
      console.log("composing"); // if true execute

      executeHandlePress = false; // toggle flag to false

      setTimeout(() => {
        executeHandlePress = true; // reset after 5 seconds
      }, DEBOUNCE_THRESHOLD);
    }
  };

  const handleMessageChange = (message) => {
    setMessageInput(message);
  };

  const handleMessagePress1 = (e) => {
    if (e.key === "Enter" || e === "send") {
      console.log("sendMessage");
    }
  };
  return (
    <React.Fragment>
      <input
        value={messageInput}
        type="text"
        id="messageInputField"
        placeholder="Write your message..."
        onKeyPress={(e) => {
          handleMessagePress(e);
          handleMessagePress1(e);
        }}
        onChange={(e) => {
          handleMessageChange(e.target.value);
          handleChange();
        }}
      />
    </React.Fragment>
  );
}
ReactDOM.render(<App />, document.body);
代码语言:javascript
运行
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>

// js中的工作片段

代码语言:javascript
运行
复制
let myInput = document.getElementById("messageInputField");
let timer;
let executeHandlePress = true; // flag to watch handle press function execution
if (myInput) {
  myInput.addEventListener("keyup", () => {
    clearTimeout(timer);
    timer = setTimeout(stop, 5000);
  });
}

const stop = () => {
  console.log("user stop typing");
}

const handleMessagePress = (e) => {
  if (!executeHandlePress) { // if flag false, return
    return;
  }
  console.log("user is typing"); // if true execute

  executeHandlePress = false; // toggle flag to false

  setTimeout(() => {
    executeHandlePress = true; // reset after 5 seconds
  }, 5000);
}
代码语言:javascript
运行
复制
<input placeholder="type your message" id="messageInputField" onKeyPress=" handleMessagePress(event)" />

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-08 10:27:13

当您在React中设置状态时,它会导致再次调用组件函数以重新呈现组件。每次渲染时,都会在此处重新声明executeHandlePress时对其进行重置:

代码语言:javascript
运行
复制
let executeHandlePress = true;

因此,无论您在此特定快照/渲染中对此变量做了什么,都不会在下一次渲染中保留下来,因为它将被重新声明。为了帮助解决这个问题,你可以创建一个ref:

代码语言:javascript
运行
复制
const executeHandlePress = useRef(true);

这样,您的布尔值将在多个渲染中持续存在。使用ref时,可以使用executeHandlePress.current引用布尔值

代码语言:javascript
运行
复制
const { useRef, useState } = React;
const DEBOUNCE_THRESHOLD = 5000;
function App() {
  const [messageInput, setMessageInput] = useState("");
  const timeoutHandler = useRef(null);
  const executeHandlePress = useRef(true);
  const handleChange = (event) => {
    if (timeoutHandler.current) {
      clearTimeout(timeoutHandler.current);
    }
    timeoutHandler.current = setTimeout(() => {
      console.log("paused");
    }, DEBOUNCE_THRESHOLD);
  };
  const handleMessagePress = (e) => {
    if (executeHandlePress.current) {
      console.log("composing"); // if true execute

      executeHandlePress.current = false; // toggle flag to false

      setTimeout(() => {
        executeHandlePress.current = true; // reset after 5 seconds
      }, DEBOUNCE_THRESHOLD);
    }
  };

  const handleMessageChange = (message) => {
    setMessageInput(message);
  };

  const handleMessagePress1 = (e) => {
    if (e.key === "Enter" || e === "send") {
      console.log("sendMessage");
    }
  };
  return (
    <React.Fragment>
      <input
        value={messageInput}
        type="text"
        id="messageInputField"
        placeholder="Write your message..."
        onKeyPress={(e) => {
          handleMessagePress(e);
          handleMessagePress1(e);
        }}
        onChange={(e) => {
          handleMessageChange(e.target.value);
          handleChange();
        }}
      />
    </React.Fragment>
  );
}
ReactDOM.render(<App />, document.body);
代码语言:javascript
运行
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69494155

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档