Input fields lose focus on each value change in a complex Formik form

Viewed 2918

I'm building an app that will need a complex form generation (from json/js object).

Here's an example of what I'm building: https://codesandbox.io/s/formik-form-wizard-test-vcj1t

My problem is the following:

all the input fields lose focus on every value change


The folder structure of the CodeSandbox project is the following (for easier code comprehension):

./src:

  • App.js - main file with all the form generation (generateWizardSteps is the main function that does all the generation).

  • formSetup.js - that's an object that defined form configuration. From objects like this I need to build dynamic forms. This object has the array of pages (these are the steps of the wizard), and each page has an array of fields (like input, select, checkbox etc). In its turn, each field has props property. props is what I pass to the React component as props.

  • formComponents.js - this file contains all the form field React components that I use for generating my forms.

  • decorateWithFormik.js - this file is just to make App.js a bit smaller. It's just the useFormik decorator.


The form is built using the formik library. Also, as I need a wizard-like form, I've found a nice library for it: formik-wizard-form.

I've looked through the stackoverflow questions on similar topics but couldn't find something that could fit my needs. Many questions/answers are about the problem with dynamic key props, but mine are static as far as I can tell (they all are taken from the initial formSetup object).

Another thing that I've noticed is that my form gets re-rendered on every value change, but I'm not sure if this is a problem at all.


Could you help me to figure out what the problem is, why does it happend and how to make my form fields not lose focus?

1 Answers

Solved the issue

I've removed all the possible component creation code and moved everything inside the component props of the Step component provided by the formik-wizard-form library.

Here's my working solution: https://codesandbox.io/s/formik-form-wizard-test-lz3x7 (hope this will help somebody)

Many thanks to everyone in the comments section!


Main insights:

  1. Losing focus means that the component unmounts and remounts every time.

  2. This unmounting/remounting behaviour on every change was caused by the creation of components inside the render function of another component. Consequently, on every re-render the input components were created anew.


My final working code:

const MyForm = props => {
  return (
    <FormikWizardProvider {...props}>
      {renderProps => (
        <Wizard {...renderProps}>
          <StepsList>
            {formSetup.pages.map(page => (
              <Step
                title={page.name}
                key={page.name}
                component={() =>
                  page.fields.map(field => {
                    if (
                      field.props &&
                      field.props.visibilityCheckbox &&
                      !props.values[field.props.visibilityCheckbox]
                    ) {
                      return null;
                    }

                    const fieldProps = {
                      formik: props,
                      key: field.props.name,
                      ...field.props
                    };

                    switch (field.type) {
                      case "input":
                        return <MyTextInput {...fieldProps} />;
                      case "radio":
                        return <RadioButtonGroup {...fieldProps} />;
                      case "checkbox":
                        return <MyCheckbox {...fieldProps} />;
                      case "select":
                        return <MySelect {...fieldProps} />;

                      default:
                        return null;
                    }
                  })
                }
              />
            ))}
          </StepsList>
          <ButtonsList>
            <PreviousButton />
            <NextButton />
            <SubmitButton />
          </ButtonsList>
        </Wizard>
      )}
    </FormikWizardProvider>
  );
};

export default decorateWizardWithFormik(MyForm);
Related