ReactJS - 具有多个输入的自动保存 - 最佳实践

标签 reactjs autosave debouncing

我想要实现的目标是实现自动保存功能而不损害性能(无用的重新渲染等)。 理想情况下,当自动保存发生时,状态也会更新。 我创建了一个具有 3 个输入的示例组件,在此示例中,该组件在每次击键时都会重新渲染。我还有一个 useEffect Hook ,在其中查找数据更改,然后在 1 秒后保存它们。 ChildComponent 用于预览输入数据。

function App(props) {
  
  const timer = React.useRef(null);  
  const [data, setData] = React.useState(props.inputData);

  React.useEffect(() => {
    clearTimeout(timer.current)
    timer.current = setTimeout(() => {
      console.log("Saving call...", data)
    }, 1000)
  }, [data])

  const inputChangeHandler = (e, type) => {
    if (type === "first") {
      setData({ ...data, first: e.target.value })
    } else if (type === "second") {
      setData({ ...data, second: e.target.value })
    } else if (type === "third") {
      setData({ ...data, third: e.target.value })
    }
  }

  return (
    <>
      <div className="inputFields">
        <input 
          defaultValue={data.first} 
          type="text" 
          onChange={(e) => inputChangeHandler(e, "first")} 
        />
        <input 
          defaultValue={data.second} 
          type="text" 
          onChange={(e) => inputChangeHandler(e, "second")} 
        />
        <input 
          defaultValue={data.third} 
          type="text" 
          onChange={(e) => inputChangeHandler(e, "third")} 
        />
      </div>
      <ChildComponent data={data} />
    </>
  )
}

我读过有关去抖动的内容,但我的实现不起作用。有人遇到同样的问题吗?

下面是我使用 lodash 实现的去抖动:

React.useEffect(() => {
  console.log("Saving call...", data)
}, [data])

const delayedSave = React.useCallback(_.debounce(value => setData(value), 1000), []);

const inputChangeHandler = (e, type) => {
  if (type === "first") {
    let obj = { ...data };
    obj.first = e.target.value;
    delayedSave(obj)
  } else if (type === "second") {
    let obj = { ...data };
    obj.second = e.target.value;
    delayedSave(obj)
  } else if (type === "third") {
    let obj = { ...data };
    obj.third = e.target.value;
    delayedSave(obj)
  }
}

此问题的问题在于,如果用户从第一个输入到第二个输入立即(在 1 秒延迟之前)键入,则只会保存最后一个用户输入。

最佳答案

您的实现中的问题是,计时器是使用组件之前数据在闭包中设置的(在useEffect中)计时器启动。一旦data(或我的实现提案中的newData)发生更改,您应该启动计时器。像这样的东西:

function App(props) {
  const [data, setData] = React.useState(props.inputData);
  const { current } = React.useRef({ data, timer: null });

  const inputChangeHandler = (e, type) => {
    current.data = { ...current.data, [type]: e.target.value };

    if(current.timer) clearTimeout(current.timer);

    current.timer = setTimeout(() => {
      current.timer = null;
      setData(current.data);
      console.log("Saving...", current.data);
    }, 1000);
  }

  return (
    <>
      <input defaultValue={data.first} type="text" onChange={(e) => inputChangeHandler(e, "first")} />
      <input defaultValue={data.second} type="text" onChange={(e) => inputChangeHandler(e, "second")} />
      <input defaultValue={data.third} type="text" onChange={(e) => inputChangeHandler(e, "third")} />
    </>
  );
}

关于ReactJS - 具有多个输入的自动保存 - 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63234259/

相关文章:

javascript - 如何从javascript中的去抖动函数返回值?

reactjs - 在 useEffect 中使用额外的依赖有什么后果?

javascript - 使用自定义属性创建 react 元素

javascript - 在 React JS 中将 Prop 传递给父级

python - 如何在 Python 中完全保存/读取类

sql - 关闭winform应用程序、自动保存选项后sql server中的数据丢失

php - 从 php 自动保存到 mysql,无需页面更改或提交按钮

javascript - 如何在 Reactjs 中循环返回复杂的 JSON?

javascript - Vuejs 2 : debounce not working on a watch option

react-hooks - 使用去抖动的 onChange 处理程序设置输入值