仅在 onChange 停止触发设定时间后,如何使 React 输入 onChange 设置状态?

Nic*_*eat 7 input onchange settimeout setinterval reactjs

介绍 我在 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

Run Code Online (Sandbox Code Playgroud)

将代码 复制并粘贴到 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;

Run Code Online (Sandbox Code Playgroud)

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

cd delay-output-app
npm start
Run Code Online (Sandbox Code Playgroud)

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

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

使用 lodash 去抖动的代码

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;


Run Code Online (Sandbox Code Playgroud)

Dam*_*ury 5

你真的不需要裁判来解决这个问题。调用useEffect应该就足够了:

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

const updateOutput = (e) => {
  setUserValue(e.target.value);
};
Run Code Online (Sandbox Code Playgroud)


小智 2

你可以尝试这个方法

const updateOutput = () => {
setUserValue(inputRef.current.value);
setTimeout(() => {setOutput(inputRef.current.value)}, 700) }
Run Code Online (Sandbox Code Playgroud)

希望对你有帮助。