如何去除最终形式的字段?
how to debounce a final-form Field?
这是一个很常见的查询,但我对新的 final-form
库有点困惑。我曾经使用 redux-form
但这个新版本太不一样了。
我的需求很简单,我想在用户输入一些文本时发送搜索,但我想在字段中添加一个 throttle
。
这是对库 react-final-form-listeners
的第一次尝试,但正如您将看到的,当您在文本字段中写入时,去抖不起作用:/
https://codesandbox.io/embed/react-final-form-simple-example-khkof
首先,我鼓励您在不使用模糊包层的情况下完成所有这些操作。这将帮助您真正理解流程,但是,当输入发生变化时,您可以通过以下方式调用函数:
- debounce(仅在用户停止输入 500 毫秒时执行一次)
- 节流(然后每 500 毫秒执行一次批处理)
- 正常(在每次输入更新时执行)
在这种情况下,我只是在渲染方法之外创建了一个去抖动函数。这在使用 classes 而不是钩子时会有所不同:
挂钩:
const handleSearch = debounce(searchText => { ... }, 500);
类(或者您可以在 constructor
中对 class 字段进行去抖动,两者都有效):
class Example extends Component {
handleSearch = debounce(searchText => { ... }, 500)
render = () => { ... }
}
工作示例(在 codesandbox 控制台打开时键入):
去抖、节流和正常执行之间的区别:
同上,减去react-final-form
和react-final-form-listeners
(项目中少了两个依赖!):
工作示例(在 codesandbox 控制台打开时键入):
您的解决方案存在多个问题:
- 使用 lodash
debounce
而不是 throttle
。
- 在表单外创建去抖功能,以防止在每次重新渲染或更改时重新分配它
- 调用表单提交操作,而不是提交处理程序
handleSubmit
修改并运行您的示例:
这是一个记忆化的去抖动版本:
export default function DebouncedMemoizedField({
milliseconds = 400,
validate,
...props
}) {
const timeout = useRef(null);
const lastValue = useRef(null);
const lastResult = useRef(null);
const validateField = (value, values, meta) => new Promise((resolve) => {
if (timeout.current) {
timeout.current();
}
if (value !== lastValue.current) {
const timerId = setTimeout(() => {
lastValue.current = value;
lastResult.current = validate(value, values, meta);
resolve(lastResult.current);
}, milliseconds);
timeout.current = () => {
clearTimeout(timerId);
resolve(true);
};
} else {
resolve(lastResult.current);
}
});
return <Field validate={validateField} {...props} />;
}
用法:
<MemoizedDebouncedValidationField
name="username"
validate={(value) => (value === 'jim' ? 'Username exists' : undefined)}
render={({ input, meta }) => (
<>
<input {...input} />
{(meta.touched && meta.error) && <p>Error</p>}
</>
)}
/>
这是一个很常见的查询,但我对新的 final-form
库有点困惑。我曾经使用 redux-form
但这个新版本太不一样了。
我的需求很简单,我想在用户输入一些文本时发送搜索,但我想在字段中添加一个 throttle
。
这是对库 react-final-form-listeners
的第一次尝试,但正如您将看到的,当您在文本字段中写入时,去抖不起作用:/
https://codesandbox.io/embed/react-final-form-simple-example-khkof
首先,我鼓励您在不使用模糊包层的情况下完成所有这些操作。这将帮助您真正理解流程,但是,当输入发生变化时,您可以通过以下方式调用函数:
- debounce(仅在用户停止输入 500 毫秒时执行一次)
- 节流(然后每 500 毫秒执行一次批处理)
- 正常(在每次输入更新时执行)
在这种情况下,我只是在渲染方法之外创建了一个去抖动函数。这在使用 classes 而不是钩子时会有所不同:
挂钩:
const handleSearch = debounce(searchText => { ... }, 500);
类(或者您可以在 constructor
中对 class 字段进行去抖动,两者都有效):
class Example extends Component {
handleSearch = debounce(searchText => { ... }, 500)
render = () => { ... }
}
工作示例(在 codesandbox 控制台打开时键入):
去抖、节流和正常执行之间的区别:
同上,减去react-final-form
和react-final-form-listeners
(项目中少了两个依赖!):
工作示例(在 codesandbox 控制台打开时键入):
您的解决方案存在多个问题:
- 使用 lodash
debounce
而不是throttle
。 - 在表单外创建去抖功能,以防止在每次重新渲染或更改时重新分配它
- 调用表单提交操作,而不是提交处理程序
handleSubmit
修改并运行您的示例:
这是一个记忆化的去抖动版本:
export default function DebouncedMemoizedField({
milliseconds = 400,
validate,
...props
}) {
const timeout = useRef(null);
const lastValue = useRef(null);
const lastResult = useRef(null);
const validateField = (value, values, meta) => new Promise((resolve) => {
if (timeout.current) {
timeout.current();
}
if (value !== lastValue.current) {
const timerId = setTimeout(() => {
lastValue.current = value;
lastResult.current = validate(value, values, meta);
resolve(lastResult.current);
}, milliseconds);
timeout.current = () => {
clearTimeout(timerId);
resolve(true);
};
} else {
resolve(lastResult.current);
}
});
return <Field validate={validateField} {...props} />;
}
用法:
<MemoizedDebouncedValidationField
name="username"
validate={(value) => (value === 'jim' ? 'Username exists' : undefined)}
render={({ input, meta }) => (
<>
<input {...input} />
{(meta.touched && meta.error) && <p>Error</p>}
</>
)}
/>