Last active
December 29, 2022 01:22
-
-
Save jaredpalmer/56e10cabe839747b84b81410839829be to your computer and use it in GitHub Desktop.
Formik-Autosave
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import PropTypes from 'prop-types' | |
import debounce from 'lodash.debounce' // or whatevs | |
import isEqual from 'lodash.isEqual' | |
class AutoSave extends React.Component { | |
static contextTypes = { | |
formik: PropTypes.object | |
} | |
state = { | |
isSaving: false, | |
} | |
componentWillReceiveProps(nextProps, nextContext) { | |
if (!isEqual(nextProps.values, this.props.values)) { | |
this.save() | |
} | |
} | |
save = debounce(() => { | |
this.setState({ isSaving: true, saveError: undefined }) | |
this.props.onSave(this.props.values) | |
.then( | |
() => this.setState({ isSaving: false, lastSaved: new Date() }), | |
() => this.setState({ isSaving: false, saveError }) | |
) | |
}), 300) | |
} | |
render() { | |
return this.props.render(this.state) | |
} | |
} | |
} | |
// Usage | |
import React from 'react'; | |
import { Formik, Field, Form } from 'formik' | |
import distanceInWordsToNow from 'date-fns/distance_in_words_to_now' | |
const App = () => | |
<div> | |
<h1>Signup form</h1> | |
<Formik | |
initialValues={{ firstName: '', lastName: ''} | |
onSubmit={values => { | |
setTimeout(() => { | |
alert(JSON.stringify(values, null,2)) | |
}, 500) | |
} | |
render={() => | |
<Form> | |
<Field name="firstName" /> | |
<Field name="lastName" /> | |
<button type="submit">Submit</button> | |
<AutoSave | |
onSave={values => CallMyApi(values) /* must return a promise 😎 */}\ | |
debounce={1000} | |
render={({isSaving, lastSaved, saveError }) => | |
<div> | |
{!!isSaving | |
? <Spinner/> | |
: !!saveError | |
? `Error: ${saveError}` | |
: lastSaved | |
? `Autosaved ${distanceInWordsToNow(lastSaved)} ago` | |
: 'Changes not saved'} | |
</div> | |
} | |
/> | |
</Form> | |
} | |
/> | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
There's one tiny problem with the solutions above - when you rely solely on
formik.dirty
, you will miss any changes that result in a field value equal toinitialValues
, as per specs:So when your Formik doesn't have
enableReinitialize
prop enabled (by default, it doesn't) and you change some field, autosave submits your form, and then you change that field once more to value equal with initial value - it won't detect that as a change.For most implementations, that may not be the case, or maybe you can use
enableReinitialize
- but I didn't want to, as users can lose the focused field when reinitialization happens. So I came up with another implementation, which holds the last submitted values in its state, and usesisEqual
fromreact-fast-compare
just as Formik internally does.You can find this implementation here: https://gist.github.com/SPodjasek/c5354da2e897daa14654674ab21c9b72