final-form / react-final-form

🏁 High performance subscription-based form state management for React
https://final-form.org/react
MIT License
7.39k stars 481 forks source link

How to retain dirty after the Rerender of the initial form component #898

Open gyto23 opened 3 years ago

gyto23 commented 3 years ago

What is the current behavior?

I am using nextjs to support multi paging and I strangle to understand how to retain a dirty within pages. The case scenario is where user is edited the form and then they release form by moving to another page. After confirming some of the information they need, user coming back to the form to continue editing it. My issue is that even if I use keepDirtyOnReinitialize prop, it saves the value of the dirty, but it doesn't actually identify the form it was dirty from first initialization nor is dirty when coming back to it. Even after I have reloaded the page by hard reload it will bring everything to initial state, where user looses everything :( In addition, I am using examples like Redux Example and Loading, Normalizing, Saving, and Reinitializing to retain the state of the form and bring it back when I needed.

What is the expected behavior?

To retain dirty after user came back to the form from different page

Sandbox Code

const FormControl = (
  {
    formName,
  },
) => {
  return (
    <LoadForm
      formName={formName}
      initialValues={{ newField: "test" }}
      onSubmit={(data) => {}}
    >
      {({ form, handleSubmit, submitting, pristine, ...rest }) => (
        <form onSubmit={handleSubmit}>
          <FormControlRedux formName={formName}/>
          <div>
            <button type="submit" disabled={submitting || pristine}>save</button>
            <button onClick={form.reset} type="button">reset</button>
          </div>

          <Field name="newField" component="input"/>
        </form>
      )}
    </LoadForm>
  );
};

const FormControlRedux = ({ formName }) => {
  const { setData } = useFormRedux(formName);
  return <FormSpy onChange={state => setData(state)}/>;
};

const LoadForm = (
  {
    onSubmit,
    formName,
    initialValues,
    ...rest
  }
) => {
  // example 1: https://codesandbox.io/s/xr0mvl1904?file=/LoadSaveReinitializeForm.js:661-675
  // example 2: https://codesandbox.io/s/4xq2qpzw79?file=/src/index.js:1312-1325
  const initialState = {
    isLoading: false,
    original: undefined,
    current: undefined,
  }
  const { data: subscription } = useFormRedux(formName);
  const reducer = (state, action) => ({ ...state, ...action })
  const [state, setState] = React.useReducer(reducer, initialState);

  const loadForm = () => {
    setState({ isLoading: true });
    const original = initialValues || {};
    const current = subscription.dirty ? subscription.values : original;
    setState({ isLoading: false, current, original });
  }

  React.useEffect(() => { loadForm();  }, [])

  return state.isLoading || !state.current
    ? <div>loading...</div>
    : <Form {...rest} {...{ subscription }} onSubmit={onSubmit}
      keepDirtyOnReinitialize={subscription.dirty}
      initialValues={state.current}
    />
}

export default FormControl;

What's your environment?

"final-form": "4.20.2", "react-final-form": "6.5.2"

smaidah commented 2 years ago

Any updates on this?