3

this is a pretty common query, but I am a bit confused with the new final-form library. I used to work with redux-form but this new version is too different.

My need is simple, I want to dispatch a search as the user writes in some text, but I want to add a throttle to the Field.

Here is a first attempt with the lib react-final-form-listeners, but as you will see, when you write in the text field, the debounce does not work :/

https://codesandbox.io/embed/react-final-form-simple-example-khkof

Patrick Ferreira
  • 1,983
  • 1
  • 15
  • 31

3 Answers3

1

First, I'd encourage you to do all of this without using an obscured package layer. This will help you truly understand the flow, but nevertheless, here's how you can call a function when the input changes:

  • debounce (only executes once when a user stops typing for 500ms)
  • throttle (batches then executes every 500ms)
  • normal (executes on every input update)

In this case, I just created a debounced function outside of the render method. This varies when using classes instead of hooks:

Hooks:

const handleSearch = debounce(searchText => { ... }, 500);

Classes (or you can debounce the class field in the constructor, either work):

class Example extends Component {
  handleSearch = debounce(searchText => { ... }, 500)

  render = () => { ... }
}

Working example (type while the codesandbox console is open):

Edit  React Final Form - Simple Example


The differences between debounced, throttled, and normal execution:

enter image description here


Same as above, minus react-final-form and react-final-form-listeners (two less dependencies in your project!):

Working example (type while the codesandbox console is open):

Edit Simple Form - Simple Example


Matt Carlotta
  • 18,972
  • 4
  • 39
  • 51
0

There are multiple issues with your solution:

  • use lodash debounce instead of throttle.
  • create debounced function outside form in order to prevent its reassign on every rerender or change
  • call form submit action, instead of submit handler handleSubmit

Modified and working your example:

Edit  React Final Form - Simple Example

Titenis
  • 555
  • 7
  • 14
0

Here's a memoized debounced version:

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} />;
}

Usage:

<MemoizedDebouncedValidationField
  name="username"
  validate={(value) => (value === 'jim' ? 'Username exists' : undefined)}
  render={({ input, meta }) => (
    <>
      <input {...input} />
      {(meta.touched && meta.error) && <p>Error</p>}
    </>
  )}
/>
onosendi
  • 1,889
  • 1
  • 7
  • 14