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")} />
</>
);
}
我想要实现的目标是在不影响性能(无用的重新渲染等)的情况下实现自动保存功能。 理想情况下,当自动保存发生时,状态也会更新。 我创建了一个包含 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")} />
</>
);
}