React输入框onBlur触发patch后短暂显示旧值的解决方案咨询
解决输入框在patch成功后短暂显示旧值的问题
问题原因
在handleBlur方法中,调用mutate提交更新后立刻执行setValue(parseFloat(cell.getValue())),此时服务器尚未完成数据更新,cell.getValue()返回的仍是旧值,导致输入框先显示旧值;待服务器更新完成后,cell.getValue()变为新值,监听该值的useEffect触发,将输入框值切换为新值,因此出现短暂显示旧值的闪烁现象。
解决方案
通过调整本地状态更新时机,避免强制覆盖为旧值,同时确保输入框立刻显示提交后的正确值:
- 移除
handleBlur末尾强制设置旧值的setValue(parseFloat(cell.getValue()))语句; - 在调用
mutate提交前,先将本地状态更新为处理后的目标值,让输入框立刻显示正确结果; - 统一状态类型为字符串,避免数字与字符串切换引发的类型不一致问题;
- 增加错误处理,确保非法输入或提交失败时状态能正确回滚。
修改后的完整代码
import { useEffect, useRef, useState } from "react"; export const TableNumberInput = ({ cell, mutate, ...restProps }: { cell: unknown; mutate: unknown; }) => { // 初始化状态为字符串,与输入框值类型保持一致 const [value, setValue] = useState(cell.getValue().toString()); const inputRef = useRef(null); useEffect(() => { // 当cell数据更新时,同步到本地状态 setValue(cell.getValue().toString()); }, [cell.getValue()]); const handleBlur = (event) => { try { const num = eval(event.target.value); const rounded_num = Math.round(num * 100) / 100; const roundedStr = rounded_num.toString(); // 先更新本地状态,输入框立刻显示处理后的值 setValue(roundedStr); if (parseFloat(value) !== parseFloat(cell.getValue())) { mutate( { id: cell.row.original.id.toString(), data: { [cell.column.id]: rounded_num }, }, { onError: () => { // 提交失败时恢复为cell原始值 setValue(cell.getValue().toString()); inputRef.current.select(); inputRef.current.focus(); }, } ); } } catch (err) { // 处理eval执行错误,恢复为原始值 setValue(cell.getValue().toString()); inputRef.current.select(); inputRef.current.focus(); } }; return ( <input ref={inputRef} value={value} onChange={(e) => setValue(e.target.value)} precision={2} onBlur={handleBlur} {...restProps} /> ); };
关键修改说明
- 移除旧值强制设置:避免提交后立刻将输入框切回旧值,消除闪烁根源;
- 提前更新本地状态:提交前先把输入框值设为处理后的结果,用户无需等待服务器响应即可看到正确显示;
- 类型统一:将状态值统一为字符串,避免数字与字符串类型切换导致的渲染异常;
- 错误处理增强:覆盖
eval执行错误和提交失败场景,确保状态能正确回滚,提升用户体验。
内容的提问来源于stack exchange,提问作者skelaw
相关产品推荐
相关产品推荐

