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

ReactJS - Autosave with multiple inputs - best practices

我想要实现的目标是在不影响性能(无用的重新渲染等)的情况下实现自动保存功能。 理想情况下,当自动保存发生时,状态也会更新。 我创建了一个包含 3 个输入的示例组件,在此示例中,该组件会在每次击键时重新呈现。我还有一个 useEffect 挂钩,我在其中寻找数据更改,然后在 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 秒延迟之前)从第一个输入到第二个输入,它只会保存最后一个用户输入。

您应该在计时器处理程序中将计时器 ID 设置为 null。

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

您的实现中的问题是计时器是在闭包中设置的(在 useEffect 中)使用 data 您的组件在计时器 之前 开始。一旦 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")} />
    </>
  );
}