Provide a set of callbacks to onSubmit method, for example reset function
feature request
<Form
onSubmit={onSubmit}
initialValues={{ employed: true }}
render={({ handleSubmit, reset }) => (
<form
onSubmit={event => {
handleSubmit(event).then(() => {
reset() // or could be passed directly to then()
})
}}
>
...
</form>
}/>
const onSubmit = (values, reset) => {
return new Promise (resolve => {
reset();
resolve();
}
};
<Form
onSubmit={onSubmit}
initialValues={{ employed: true }}
render={({ handleSubmit, reset }) => (
<form onSubmit={handleSubmit}>
...
</form>
}/>
It _could_ do this, but you already have a decent option available. I鈥檓 not sure we should provide six ways to do everything.
@erikras As mentioned in #21, you dont always have a luxury to use promises, for example when using redux-saga. What I am forced to do is below code:
let resetForm;
class EditUserDataForm extends Component {
handleSubmit = (values, setErrors) => {
this.props.editUser(values, setErrors, resetForm);
};
render() {
return (
<Form
onSubmit={this.handleSubmit}
render={({ handleSubmit, reset }) => (
<form
onSubmit={(e) => {
resetForm = reset;
handleSubmit(e);
}}
>
...
</form>
)}
/>
);
}
}
which I really don't like. I could also do this.resetForm = reset, but still, I just feels like a hack because I don't have access to form wide actions in onSubmit, whereas this is the place where those actions belong. We have an access to form values in Form.onSubmit, and often we also need some form mutators, like setValidationError (which we already have, but only to this one, which is not consistent), reset, blur, change. And now, we need to create this bridge in form.onSubmit. What I recommend is the following:
<Form
onSubmit={(values, { reset, setSubmitError, focus, blur, change, batch, mutators }) => {
...
}}
...
</Form>
where setSubmitError is the old callback. This is more or less how Formik does this, which allows so much flexibility where this is often so needed - during the form submit.
@erikras how do you propose to handle callbacks when not disabling your submit on invalid? handleSubmit.then(reset) will not work if you never get to your onSubmit function to return the Promise.
@stunaz I wouldnt just pass reset to the onSubmit function, rather a set of actions (ie: formikBag)
I wouldnt just pass reset to the onSubmit function, rather a set of actions
Yes, this is obvious. The whole FormApi could be provided, even.
Fixed published in [email protected] and [email protected].
I came here with almost the same issue as @klis87, and thought I'd post my implementation using the FormAPI that's now available in the callback.
My form:
class LoginForm extends React.Component<Props> {
handleLogin = (credentials: Credentials, formAPI): void => {
const { reset } = formAPI
this.props.loginUser({ credentials, failureCallback: reset })
}
render() {
return (
<Form
// ... Omitted for simplicity, nothing fancy here
/>
)
}
}
My Sagas:
function* loginSaga(params: { credentials: Credentials, onFailure: () => void, onSuccess: () => void }): Saga<void> {
try {
// authenticateUser is a basic AJAX call that resolves on a successful login, rejects with bad credentials
const user = yield call(authenticateUser, params.credentials)
if (params.onSuccess) yield call(params.onSuccess)
yield put({ type: LOGIN_SUCCESS, payload: user })
} catch (error) {
if (params.onFailure) yield call(params.onFailure)
yield put({ type: LOGIN_FAILURE, payload: { loginError: error.message } })
}
}
I'm so used to promises that callbacks feel 'hacky' at this point, but I can't figure out a more elegant way to work with Redux.
@klis87, I'd be curious to see how you ended up doing this if you have any insights!
@erikras I'd second the request to have some kind of setSubmitError method within the Form API (or even a setErrors method that can be used on fields as well). I'm guessing that this would be an issue in the main final-form repo, correct? Or, do you have any suggested ways to handle this?
@good-idea I did it in similar way like you, just passing callbacks to redux actions. Passing callback is required due to how redux-saga works, final-form cannot help you with this, because you cannot know in component when a saga execution is finished - action wont return promise like in case of redux-thunk. For me this is not so much of a deal, but unfortunately saga and redux needs to use those provided form callbacks which really dont belong to redux, but to react and UI. As an alternative, see this library https://github.com/diegohaz/redux-saga-thunk , I didnt use it, but I might consider to check it out at some point.
Passing callback is required due to how redux-saga works, final-form cannot help you with this, because you cannot know in component when a saga execution is finished
Final Form _does_ allow passing a callback. However, I don't know enough about Redux-Saga to know if that helps, but it _is_ sort of the equivalent of having a setSubmitError.
Fantastic, thanks to both of you.
@erikras would it be helpful to make a Final Form + Redux-Saga example?
It _would_! But I'm not the one to do it. I'd be glad to link to it in the README.
Oh of course, yes, I mean that I'd put one together. Hopefully early next week!
Another way to do it is to wrap actual action in promise and send resolve/reject with it.
submit(values) {
return new Promise((resolve, reject) => {
updateAction({ values, resolve, reject });
});
}
Then in saga you can call yield call(resolve, ...) or reject.
So promises will be there and it will be possible to use .then(reset).
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Oh of course, yes, I mean that I'd put one together. Hopefully early next week!