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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

FieldArray removing item gives old array from props #2934

Closed
nirvparekh opened this issue Nov 28, 2020 · 4 comments
Closed

FieldArray removing item gives old array from props #2934

nirvparekh opened this issue Nov 28, 2020 · 4 comments
Labels

Comments

@nirvparekh
Copy link

nirvparekh commented Nov 28, 2020

馃悰 Bug report

Current Behavior

I'm implementing invoice module in my app. where user can add invoice items dynamically handled by Formik's FieldArray. User can add/remove items.

When user removes a particular index from FieldArray, it removes from array and reflected in DOM. working fine. But after arrayHelper.remove(), Formik props props.values.invoice_items still giving old array in console.

Expected behavior

after arrayHelper.remove(), Formik props props.values.invoice_items should give updated array.

Reproducible example

Here's my snippet

<Formik
  enableReinitialize
  initialValues={{
    invoice_items: [{ name: "", qty: 0, rate: 0, amount: 0 }],
  }}>
  {(props) => (
    <form onSubmit={props.handleSubmit}>
      <FieldArray
        name="invoice_items"
        render={(arrayHelpers) => (
          <React.Fragment>
            {props.values.invoice_items.map((item, index) => (
              <div className="form-group" key={index}>
                <Field name={`invoice_items.${index}.name`}>
                  {({ field }) => (
                    <>
                      <input
                        {...field}
                        placeholder="Item name"
                        className="form-control"
                        autoFocus/>
                        {props.values.invoice_items.length > 1 && (
                          <button
                            className="remove-item"
                            onClick={() => {
                              arrayHelpers.remove(index)

                              console.log(props.values.invoice_items)
                              /* --- HERE IT STILL GIVES OLD ARRAY --- */
                            }}>
                          Remove
                        </button>
                      )}
                    </>
                  )}
                </Field>
              </div>
            ))}
          </React.Fragment>
        )}
      />
    </form>
  )}
</Formik>

Your environment

Software Version(s)
Formik 2.1.4
React 16.8.6
@johnrom
Copy link
Collaborator

johnrom commented Nov 30, 2020

@nirvparekh props.values is an immutable reference to Formik's values that is passed down from React Context. It is bound to the current render, and is not updated until the next render. In the current Formik API, you should access changes to that value via an effect w/ useEffect like:

useEffect(() => {
  console.log(props.values.invoice_items);
}, [props.values.invoice_items]);

@nirvparekh
Copy link
Author

@nirvparekh props.values is an immutable reference to Formik's values that is passed down from React Context. It is bound to the current render, and is not updated until the next render. In the current Formik API, you should access changes to that value via an effect w/ useEffect like:

useEffect(() => {
  console.log(props.values.invoice_items);
}, [props.values.invoice_items]);

I'm using class based component and this is Formik's props, not parent component props that we put under componentDidUpdate

@johnrom
Copy link
Collaborator

johnrom commented Dec 3, 2020

Whether you're using functional or class-based components, the values within values will never change in a given render. I am experimenting with adding a redux-like getState() fn that would allow a dev to do getState().values to get the current value at any given point in time. However, this isn't available in the current Formik API so you'll have to use a child component with an effect.

You can rewrite your component like the following. Note that I haven't used class components in a while, so I wrote the child component functionally. However, you can achieve the same thing with class components if you like.

// original class-based render
class MyClassBasedForm {
  render() {
    <Formik 
      enableReinitialize
      initialValues={{
        invoice_items: [{ name: "", qty: 0, rate: 0, amount: 0 }],
      }}
    >
      <MyFunctionalForm />
    </Formik>
  }
}

// new form child component leveraging functional powers
const MyFunctionalForm = () => {
  const formik = useFormikContext();
  const [removeCount, setRemoveCount] = React.useState(0);

  useEffect(() => {
    console.log("An invoice was removed. The new values are: ", formik.values.invoice_items);
  }, removeCount);

  return (
    <form onSubmit={formik.handleSubmit}>
      <FieldArray
          name="invoice_items"
          render={(arrayHelpers) => (
            <React.Fragment>
                {formik.values.invoice_items.map((item, index) => (
                  <div className="form-group" key={index}>
                      <Field name={`invoice_items.${index}.name`}>
                      {({ field }) => (
                          <>
                            <input
                              {...field}
                              placeholder="Item name"
                              className="form-control"
                              autoFocus
                            />
                            {formik.values.invoice_items.length > 1 && (
                            <button
                                className="remove-item"
                                onClick={() => {
                                  arrayHelpers.remove(index);
                                  setRemoveCount(removeCount + 1);
                                }}
                            >
                              Remove
                            </button>
                            )}
                          </>
                      )}
                      </Field>
                  </div>
                ))}
            </React.Fragment>
          )}
      />
    </form>
  );
}

@github-actions
Copy link
Contributor

github-actions bot commented Jan 3, 2021

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days

@github-actions github-actions bot added the stale label Jan 3, 2021
@github-actions github-actions bot closed this as completed Mar 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants