Formik Form not updating with onclick

Viewed 979

I have a custom event handler (when clicked on a button) that injects data in the nested arrays based on a drop down selection. After the event handler added the data the form doesn't update properly. Calling any other event handler on any other input of the form will trigger the form update. The data is set correctly but the form doesnt update properly after the initial onClick event (see code)

I have enableReinitialize set

https://codesandbox.io/s/updateissue-fy72h

import { useEffect, useState } from "react";
import { Formik, Form, Field, FieldArray, TextField } from "formik";

export default function Design() {
  const q = {
    questions: ["a", "b", "c", "d"],
    selectedLanguage: "nl",
  };
  const [questionnaire, setQuestionnaire] = useState(q);

  function addLanguageValue() {
    questionnaire.questions.push(questionnaire.selectedLanguage);

    setQuestionnaire(questionnaire);
  }

  return (
    <div>
      <Formik
        initialValues={questionnaire}
        enableReinitialize
        onSubmit={() => {}}
      >
        {({ values, handleChange }) => (
          <Form>
            <div>
              <Field as="select" name="selectedLanguage">
                <option value="fr">French</option>
                <option value="nl">Dutch</option>
                <option value="en">English</option>
              </Field>

              <button
                type="button"
                className="bg-gradient-to-b"
                onClick={(e) => {
                  addLanguageValue(values);
                }}
              >
                Add language
              </button>
            </div>
            <div>
              <FieldArray
                name="questions"
                render={(rootHelper) => (
                  <div>
                    {values.questions.map((value, j) => {
                      return <div>{value}</div>;
                    })}
                  </div>
                )}
              />
            </div>
          </Form>
        )}
      </Formik>
2 Answers

You're mutating the state object, which causes the problem. If you create a fresh object in addLanguageValue, it works as expected:

  function addLanguageValue() {
    setQuestionnaire({
      ...questionnaire,
      questions: [...questionnaire.questions, questionnaire.selectedLanguage]
    });
  }

Sandbox example

Because the onClick function doesn't cause a re-render of the state, you can use the following work around / trick by using an inoffensive function as setStatus to trigger re-render:

<button
  type='button'
  className='bg-gradient-to-b'
  onClick={e => {
    addLanguageValue(values);
    //Used for rerendering.
    props.setStatus('Adding language!');
  }}
>
  Add language
</button>;
Related