Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slow on large form. #671

Closed
joonhocho opened this issue Jun 1, 2018 · 40 comments
Closed

Slow on large form. #671

joonhocho opened this issue Jun 1, 2018 · 40 comments

Comments

@joonhocho
Copy link

I have a large form with 20~30 fields.
It seems formik becomes slow when there are large number of fields.
It seems to validate every field on every keystroke.
Is there a good way to mitigate this issue?

@jaredpalmer
Copy link
Owner

Use <FastField />

@joonhocho
Copy link
Author

@jaredpalmer Can I use FastField in place for all Field without any changes? Any documentations on this? Thank you!

@jaredpalmer
Copy link
Owner

<FastField> is best used on pure fields that don't impact other fields either by changing another field's value or error message. State is kept locally in FastField and then synced up to the top level <Formik/> component once onBlur is called.

@joonhocho
Copy link
Author

@jaredpalmer Thank you I will try and report back if there are any issues.

@hmaurer
Copy link

hmaurer commented Jun 10, 2018

One issue I have found with <FastField> is that since the state is synced on blur, if the form is submitted by pressing Enter in a field, the latest value of that field won't be synced before submit. That's particularly annoying, and I haven't yet found a work-around that doesn't involve patching FastField :(

@derekcannon
Copy link

derekcannon commented Jun 11, 2018

@hmaurer Could you wrap handleChange in a function that triggers onBlur if the Enter key is pressed? (As a temporary fix)

@jaredpalmer
Copy link
Owner

You can use shouldComponentUpdate to wrap Field to optimize perf

@Virgomax
Copy link

Virgomax commented Jul 30, 2018

I have the same issue than @hmaurer with <FastField>. Please, is there going to be a fix? or a nice workaround?

For now, I'm just using something like:

({ field, form, ...props }) => {
	const onKeyDown = (e)=>{
		if (e.key == "Enter") {
			e.stopPropagation();
			form.setFieldValue(field.name, e.target.value, false);
		}
	}
	//more code here
	return <input {...field}  onKeyDown={onKeyDown}>
}

@mdmad7
Copy link

mdmad7 commented Sep 26, 2018

using create react app and semantic ui i built ~40 fields. input is very slow whilst running the app in dev mode. but when i run yarn build and run the app with serve -s build, there is no delay in input fields. can i expect the same results in whilst running on a production server?

@jaredpalmer
Copy link
Owner

Use FastField. It works now.

@rohanBagchi
Copy link

Try this maybe:
#1026 (comment)

@anand-neema
Copy link

I have 1206 fields on the page and i am using FastField as well and it's veryyyyy slow any suggestion to improve this?

Basically i am using table and all 200 rows are inline editable with 6 columns. That takes too long to compare in shouldUpdate

@jaredpalmer
Copy link
Owner

@anand-neema formik is really not designed to be performant on forms with that many fields or spreadsheet-like UI.

@wellyal
Copy link

wellyal commented Aug 30, 2019

It may be a noob question. Even though how can I use FastField If I use a third part input component like material-ui's TextField

@johnrom
Copy link
Collaborator

johnrom commented Aug 30, 2019

@anand-neema I imagine if it really is a table, each row would have the same fields with a different entity being edited (like a bulk editor). In this case, I would allow a user to only edit the rows they need to by clicking "Edit Row" and replacing that row with a Formik-ized version of the row. Multiple instances of Formik can be applied to each row. On each submit, turn that row back to the static version of the row. I still don't think it will be fast, but it might be faster. You can also add pagination to help.

Think of it like this

const MyTabularForm = (props) => (
    <table>
        {props.data.map((row, index) => (
            <tr>
                {props.editing[index] ? 
                    <FormikRow {...row} />
                    <NonFormikRow {...row />
             </tr>
        )}
    </table>
);

@wellyal check out the discord for quick questions / help or try opening a new issue if you think you've found a bug or a need for more documentation.

@anand-neema
Copy link

anand-neema commented Aug 31, 2019

@johnrom thanks for your suggestions. I Was planning that only and yes it's fast now...... But was thinking about validation stuff consider this scenario

I have mandatory field in a row and then i have click on another row, how will i maintain that error and disable the submit button ...as now field is unmounted and i am showing non formik field instead of formik field... how will error will get persist ?

Basically i am not sure how we can persist the errors of formik? Specially in this scenario

@johnrom
Copy link
Collaborator

johnrom commented Sep 2, 2019

There is a way to persist the error into your container's state using an effect like the one documented here: #1633 (comment)

If you create a form listener component that checks Formik's prop for changes and records it to the parent component.

I'd use that component like:

const MyFormWrapper = ({currentIndex}) => {
    const [errors, updateErrors] = React.useState([]);

    const errorHandler = React.useCallback((newErrors) => updateErrors([
        ...errors,
        [currentIndex]: newErrors
    ]), [currentIndex, errors]);

    return (
        <Formik initialState={getInitialState(currentIndex)} initialErrors={errors[currentIndex]}>
            // ...
            <ErrorListener onChange={errorHandler} />
        </Formik>
    )
}

(I believe initialErrors is implemented in v2 (I could be wrong or it could not be merged yet). If not or you're using v1, you'll have to show error messages with formikProps.errors.myField || errors[currentIndex].myField && <ErrorMessage />

@kevinvugts
Copy link

@anand-neema formik is really not designed to be performant on forms with that many fields or spreadsheet-like UI.

Hey Jared,

Should this be an issue with 50-100 input fields? I am experiencing a laggy input field.
Please let me know if this is fixable. I am already using FastField.

Best,
Kevin

@johnrom
Copy link
Collaborator

johnrom commented Nov 26, 2019

@kevinvugts there are numerous reasons input can be slow. Once you achieve that many active fields, it's possible Formik would have some slow rendering, depending on many factors including:

  • React / Formik versions,
  • whether you're using functional or class components,
  • if you're minimizing renders (memoization, shouldComponentUpdate) where possible in your userland code,
  • if you're performing expensive actions in userland code, and
  • if you're using third party inputs or style packages, whether they optimize their own renders

I'd recommend trying to create the name number / type of basic fields without third parties or userland code, in a codesandbox and seeing if the issue occurs there. It will also be helpful to run the profiler to make sure that the render time is spent in Formik code / React rendering and not something external. Codesandbox itself may add some overhead to rendering, so reproing in a simple CRA repo might be even better.

Ultimately though, you may find that the large number of fields is problematic. If this is the case, I'd recommend opening a new issue with reproduction, but I'd also suggest considering alternative rendering methods including breaking the form up into smaller parts which are editable, like a single row in a spreadsheet or form-wizard style pagination within formik. It can also be helpful for user experience to break down forms into smaller, digestible pieces, depending on your use case.

@wnadurski
Copy link

Hi Jared, I have several fields in my form and also experience problems with slowness. I also use Material UI so I assume that both libraries together may be less performant. I tried using FastField in my code, but it doesn't help at all. I may be not using it properly.

Here is code sandbox with my problem:
https://codesandbox.io/s/ecstatic-microservice-hz3p6?fontsize=14&hidenavigation=1&theme=dark

Fast field seems to rerender even, when other fields are being changed, as you can observe in console.

Regards

@kevinvugts
Copy link

Hi Jared, I have several fields in my form and also experience problems with slowness. I also use Material UI so I assume that both libraries together may be less performant. I tried using FastField in my code, but it doesn't help at all. I may be not using it properly.

Here is code sandbox with my problem:
https://codesandbox.io/s/ecstatic-microservice-hz3p6?fontsize=14&hidenavigation=1&theme=dark

Fast field seems to rerender even, when other fields are being changed, as you can observe in console.

Regards

I have the exact same issue indeed. How can we solve this @jaredpalmer ?

@kevinvugts
Copy link

@kevinvugts there are numerous reasons input can be slow. Once you achieve that many active fields, it's possible Formik would have some slow rendering, depending on many factors including:

  • React / Formik versions,
  • whether you're using functional or class components,
  • if you're minimizing renders (memoization, shouldComponentUpdate) where possible in your userland code,
  • if you're performing expensive actions in userland code, and
  • if you're using third party inputs or style packages, whether they optimize their own renders

I'd recommend trying to create the name number / type of basic fields without third parties or userland code, in a codesandbox and seeing if the issue occurs there. It will also be helpful to run the profiler to make sure that the render time is spent in Formik code / React rendering and not something external. Codesandbox itself may add some overhead to rendering, so reproing in a simple CRA repo might be even better.

Ultimately though, you may find that the large number of fields is problematic. If this is the case, I'd recommend opening a new issue with reproduction, but I'd also suggest considering alternative rendering methods including breaking the form up into smaller parts which are editable, like a single row in a spreadsheet or form-wizard style pagination within formik. It can also be helpful for user experience to break down forms into smaller, digestible pieces, depending on your use case.

Hi,

Thanks for our extensive reaction this really helps! How would you split up the form into chunks? Right now I have the following code:

Multiform.js
https://pastebin.com/4vv3AJtA

Builder.js
https://pastebin.com/CPiSxdNb

Could you give it a quick look to check for potential performance issues? Thanks in advance!

Best,
Kevin

@wnadurski
Copy link

My current fix is to wrap my custom components that are rendered by the FastField with either React.memo() or useMemo() and memoize it by things that FastField is supposed to update. You can see example here:

https://codesandbox.io/s/formik-fast-field-hz3p6?fontsize=14&hidenavigation=1&theme=dark

It does help a bit, however it looks like the FastField wasn't working properly.

@kevinvugts
Copy link

My current fix is to wrap my custom components that are rendered by the FastField with either React.memo() or useMemo() and memoize it by things that FastField is supposed to update. You can see example here:

https://codesandbox.io/s/formik-fast-field-hz3p6?fontsize=14&hidenavigation=1&theme=dark

It does help a bit, however it looks like the FastField wasn't working properly.

Doesn't solve it for me. Can you have a look into my code (on the top of)what's causing the slow typing?

@wnadurski
Copy link

wnadurski commented Nov 28, 2019

Doesn't solve it for me. Can you have a look into my code (on the top of)what's causing the slow typing?

Looking at your code I can't tell why it's slow - I don't see how many fields you render. I guess at least several, in my case it's where it starts slowing down. In your code you depend on the FastField to make it more performant, which in my case doesn't help. In my case my custom memoization did help, but not to a point where I am satisfied, but it's because I'm using also FieldArray and a very complex state, which I will try to memoize next and let you know whether it helped.

If you want to check what slows u down, try the React's profiler tool. What I do is starting the profiler, typing just one letter in a text field and then stopping the profiler. Then I investigate the recorder scenario, that's how I came to a conclusion that FastField rerenders its children even when some other field changes.

@kevinvugts
Copy link

Doesn't solve it for me. Can you have a look into my code (on the top of)what's causing the slow typing?

Looking at your code I can't tell why it's slow - I don't see how many fields you render. I guess at least several, in my case it's where it starts slowing down. In your code you depend on the FastField to make it more performant, which in my case doesn't help. In my case my custom memoization did help, but not to a point where I am satisfied, but it's because I'm using also FieldArray and a very complex state, which I will try to memoize next and let you know whether it helped.

If you want to check what slows u down, try the React's profiler tool. What I do is starting the profiler, typing just one letter in a text field and then stopping the profiler. Then I investigate the recorder scenario, that's how I came to a conclusion that FastField rerenders its children even when some other field changes.

@wnadurski this is the fields json: https://pastebin.com/Cnb2pJwt

Could it be the map function which is being called over and over again on each render?

@cristiancedenogallego
Copy link

I noticed that onchange callback mutate every times
any value in form changes, it forces update on all form field included Pure Components

@Bluefitdev
Copy link

It may be a noob question. Even though how can I use FastField If I use a third part input component like material-ui's TextField

Yeah I'm kind of using many custom components that use hooks useField, so I'm kind of hoping the useFastField hook #1772 would be implemented soon.. Otherwise big forms are very slow to update. Some of the use cases include multiple form groups with conditional hide and show that makes it very slow to re-render...

Anyone has luck on implementing custom form components without updating the whole forms?

@tonysepia
Copy link

@MDMAD

using create react app and semantic ui i built ~40 fields. input is very slow whilst running the app in dev mode. but when i run yarn build and run the app with serve -s build, there is no delay in input fields. can i expect the same results in whilst running on a production server?

This has helped me! With a production build things are much faster!

@nghongphuong94
Copy link

using create react app and semantic ui i built ~40 fields. input is very slow whilst running the app in dev mode. but when i run yarn build and run the app with serve -s build, there is no delay in input fields. can i expect the same results in whilst running on a production server?

You saved my day! The production build is a lot better performance!

@peraltafederico
Copy link

@mdmad7

using create react app and semantic ui i built ~40 fields. input is very slow whilst running the app in dev mode. but when i run yarn build and run the app with serve -s build, there is no delay in input fields. can i expect the same results in whilst running on a production server?

You saved my Saturday! 😆 Thanks for the hint!

@peraltafederico
Copy link

@jaredpalmer

<FastField> is best used on pure fields that don't impact other fields either by changing another field's value or error message. State is kept locally in FastField and then synced up to the top level <Formik/> component once onBlur is called.

Why isn't FastField the default then? 🤔

@johnrom
Copy link
Collaborator

johnrom commented Mar 28, 2021

@peraltafederico because users often need effects triggered on Change and not on Blur. V3 will have the best of both worlds by using subscription slicing to achieve render independence between all components instead of delaying updates. In my opinion this would deprecate FastField, or at least make it an edge case.

@peraltafederico
Copy link

@peraltafederico because users often need effects triggered on Change and not on Blur. V3 will have the best of both worlds by using subscription slicing to achieve render independence between all components instead of delaying updates. In my opinion this would deprecate FastField, or at least make it an edge case.

Sounds good!

@ChristianBermas
Copy link

You can try in formik SetFieldValue('fieldname', value, false) you can set shouldvalidate to false

@sudipstha08
Copy link

Encountered the same issue while dealing with form with large number of form fields. I solved it with this workaround.

  const FastTextField: FC<IProps> = ({ name, handleChange, value }) => {
    const [localValue, setLocalValue] = useState("");
  
    useEffect(() => {
      value && setLocalValue(value);
    }, [value]);
  
    const debouncedValue = useDebounce(localValue, 200);
  
    useEffect(() => {
      handleChange(localValue);
    }, [debouncedValue]);
  
    return (
      <TextField
        name={name}
        value={localValue}
        onChange={(e: any) => setLocalValue(e.target.value)}
        type="text"
      />
    );

And use this fast field something like this

   <FastTextField
      name={`person[${i}]`}
      error={touched && errors}
      type="text"
      value={item}
      className="text-field"
      handleChange={(value) =>
        formik.setFieldValue(
          `person[${i}]`,
          value
        )
      }
    />
  };

@rasmus-rudling
Copy link

using create react app and semantic ui i built ~40 fields. input is very slow whilst running the app in dev mode. but when i run yarn build and run the app with serve -s build, there is no delay in input fields. can i expect the same results in whilst running on a production server?

I was just going to re-write my application with ~30 fields before I saw your comment, you saved me from a days work!:medal_military:

@shamseerahammedm
Copy link

@anand-neema formik is really not designed to be performant on forms with that many fields or spreadsheet-like UI.

Straight forward answer, i hope v3 would solve the performance issues

@Huiet
Copy link

Huiet commented Oct 12, 2022

I don't know if this is specific to formik, but I had issues similar to this and one solution was to split my form into separate components and have them conditionally render based on some expandable boolean.

This cuts down renders as long as not all sections open at once. Worked for my use case

@kien-pham
Copy link

kien-pham commented Dec 19, 2022

I have same issue, I have many fields, splited to many child components. Each child I pass below props from formikProps

<ChildForm bulk={bulk} errors={errors} touched={touched} values={values} setFieldValue={setFieldValue} />

Should I use setFieldValue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests