Search code examples
reactjsnext.jsantdformik

Inputs are re-rendered whenever there is change


I have this modal and I have a formik object created. All the inputs are getting rerendered every change I type

Formik object

const formik = useFormik({
        enableReinitialize: true,
        initialValues: {
            sp_id: data?.id,
            websites: data?.websites || [],
            create_websites: [],
            delete_websites: [],
            update_websites: []
        },
        validationSchema: Yup.object({
            sp_id: Yup.string().required("This field is required and  can\'t not be changed"),
            websites:Yup.array().of(Yup. string())
        }),
        onSubmit: (values) => {
            console.log('submit:',values)
        }
    });

Form Input

const FormInput = ({ name, value, placeholder, ...rest }) => (
        <div className="space-y-1 w-full pt-3 pr-2">
            <label className="font-bold text-sm text-secondary">
                Web Link
                <span className="text-red-500">*</span>
            </label>
            <Input
                {...formik.getFieldProps(name)}
                value={value}
                placeholder={placeholder}
                onChange={(e) => {
                    formik.handleChange(e);
                    formik.setFieldValue(name, e.target.value);
                }}
                {...rest}
            />
        </div>
    );

and I am using ant design

<Form.List name="websites">
                    {(fields, {add, remove}) => {
                        return (
                            (
                                <div key="test">
                                    {
                                        fields.map(({name, key, isListField, fieldKey, ...restField}) => {
                                            return (
                                                <div key={fieldKey}>
                                                    <Form.Item
                                                        {...restField}
                                                        name={[name, 'domain']}
                                                        fieldKey={[fieldKey, 'domain']}
                                                        validateTrigger={["onChange", "onBlur"]}
                                                        rules={[
                                                            {
                                                                required: true,
                                                                message: 'Domain is required'
                                                            }
                                                            
                                                        ]}
                                                        noStyle
                                                        className="w-full"
                                                    >
                                                        <div className="flex items-end w-full">
                                                            <FormInput
                                                                name={`websites.${key}.domain`}
                                                                placeholder="URL" 
                                                                value={formik.values.websites[key]?.domain}
                                                            />
                                                            {fields.length > 1 && (
                                                                <Button
                                                                    type="default"
                                                                    size="small"
                                                                    icon={<LuTrash2 size={20}/>}
                                                                    onClick={() => {
                                                                        if (formik.values.websites[key]) {
                                                                            formik.setFieldValue(
                                                                                'delete_websites',
                                                                                [
                                                                                    ...formik.values.delete_websites,
                                                                                    formik.values.websites[key]
                                                                                ]
                                                                            );
                                                                            remove(name)
                                                                        }
                                                                    }}
                                                                    className="mb-1 bg-[#F06548]  border-[#F06548] text-white flex items-center justify-center h-full"
                                                                />
                                                            )}
                                                        </div>
                                                    </Form.Item>
                                                </div>
                                            );
                                        }
                                    )}
                                    <div className="mt-5 w-full">
                                        <AntButton
                                            type="dashed"
                                            onClick={() => {
                                                add();
                                            }}
                                            icon={<PlusOutlined />}
                                            className="w-full border-2 border-dashed border-gray-500"
                                        >
                                            Add Website
                                        </AntButton>
                                    </div>
                                </div>
                            )
                        );
                    }}
                </Form.List>

The problem is that on every change I make it the input is getting unfocused / re-rendered

Im Trying to handle on change smoothly and not to cause any re-render


Solution

  • So Instead of pursuing using Ant Design's Form List I used Formik's, Formik component, Form, FieldArray, and Field.

    const Index = ({data, isOpen, setIsOpen, mutate}) => {
      
      const validationSchema = Yup.object({});
      
      const initialValues = {};
    
      const handleSubmit = async (values, resetForm) => {};
      
      const handleAdd = (values, values) => {};
      
      const handleChange = (form, name, value) => {};
      
      return (
        <Formik
          initialValues={initialValues}
          validationSchema={validationSchema}
          enableReinitialize={true}
        >
          {(formikProps) => (
            <Modal {...actions}>
              <Form onFinish={() => handleSubmit(formikProps.values, formikProps.resetForm)}>
                {({ field, meta }) => (
                      <Input
                        {...field}
                        onChange={(e) => {
                          field.onChange(e);
                          handleChange(formikProps, field.name, e.target.value);
                        }}
                      />
                )}
              </Form>
            </Modal>
          )}
        </Formik>
      );
    }