首页 > 解决方案 > 仅在 onChange 停止触发设定时间后,如何使 React 输入 onChange 设置状态?

问题描述

简介 我在 create-react-app 应用程序中有一个用户输入元素。它允许用户键入一个数字,或使用箭头向上或向下增加数字。然后输出显示这个数字。

在此处输入图像描述

问题 用户想要到达某个数字,无论他们如何输入数字,都会有虚假的中间值触发 onChange 事件监听器。如果用户尝试用键盘输入“15”,输出首先是“1”,然后是“15”,但我希望它只是“15”。我不想使用按钮/提交/等或其他事件。如果用户按住从 0 到 500 的向上箭头,我想在“快速变化”输入减慢/停止后直接更新到 500。

目标我想编写一个 onChange 函数,以便仅当 onChange自上次事件以来至少 600 毫秒触发事件 时才更新输出。

详细信息 如果用户键入“1”然后键入“5”(表示“15”)的间隔小于 600 毫秒,则输出应更新为“15”,并跳过“1”。但是,如果用户在输入“1”和“5”之间花费的时间超过 600 毫秒,那么输出应该首先是“1”,然后是“5”。同样,如果用户上下快速按下增量箭头,则输出不应该更新,直到它们停止或减速。

在终端中,使用 create-react-app 创建一个反应应用程序

create-react-app delay-output-app

复制代码 并将其粘贴到 delay-output-app/src/App.js 中,替换所有以前的代码。

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

function App() {
  const inputRef = useRef();
  const [userValue, setUserValue] = useState(0);
  const [output, setOutput] = useState(0);

  const updateOutput = () => {
    setUserValue(inputRef.current.value);
    setOutput(inputRef.current.value);
    //if input is changing quickly - do not update output
    //only update output if input has not changed for 700ms since last change.
  };

  return (
    <div className="App">
      <br></br>
      <div>
        <h1>Input</h1>
        <input
          ref={inputRef}
          value={userValue}
          type="number"
          onChange={updateOutput}
        ></input>
      </div>
      <br></br>
      <div>
        <h1>Output</h1>
        {output}
      </div>
    </div>
  );
}

export default App;

在终端中运行应用程序...

cd delay-output-app
npm start

我尝试过使用 setTimeout 和 setInterval,但我一直遇到问题,尤其是与 react useEffect 挂钩时。同样,我不想使用按钮或让用户除了输入数字或单击箭头来更新输出之外需要按任何东西。只有输入值之间的时间决定了输入值何时是中间值或应该更新输出。

更新以包括去抖动- 我的印象是去抖动不应该在输入事件结束之前运行,但我仍然在等待期之后获得更新输出,无论用户输入事件是否结束。

带有 lodash debounce 的代码

import React, { useState, useRef } from "react";
import "./App.css";
import _ from "lodash";

function App() {
  const inputRef = useRef();
  const [userValue, setUserValue] = useState(0);
  const [output, setOutput] = useState(0);

  const updateOutput = _.debounce(
    () => setOutput(inputRef.current.value),
    700
  );
  //if input is changing quickly - do not update output
  //only update output if input has not changed for 700ms since last change.

  const updateUserValue = () => {
    setUserValue(inputRef.current.value);
  };
  return (
    <div className="App">
      <br></br>
      <div>
        <h1>Input</h1>
        <input
          ref={inputRef}
          value={userValue}
          type="number"
          onChange={() => {
            updateOutput();
            updateUserValue();
          }}
        ></input>
      </div>
      <br></br>
      <div>
        <h1>Output</h1>
        {output}
      </div>
    </div>
  );
}

export default App;


标签: reactjsinputsettimeoutsetintervalonchange

解决方案


你真的不需要 ref 来解决这个问题。一个电话就useEffect足够了:

useEffect(() => {
  const timeout = setTimeout(() => {
    setOutput(userValue);
  }, 600);
  return () => {
    clearTimeout(timeout);
  };
}, [userValue]);

const updateOutput = (e) => {
  setUserValue(e.target.value);
};

推荐阅读