-
-
Notifications
You must be signed in to change notification settings - Fork 355
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’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Form persistence #561
base: main
Are you sure you want to change the base?
Form persistence #561
Conversation
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. |
This is incredible work! I'll have to think more about this issue when I have a bit more time, but at first glance(s) I think you're more than on the right track. I'll follow-up this weekend sometime to add thoughts on what we have opinions on. In the meantime, let's see if the community has any thoughts on this API |
Framework Adapter API
useForm({
formPersister: useFormPersister({
persistKey: ['myFormKey']
})
}) This would do a few things for us: 1a) Match TanStack Query's APIs for a more consistent cross-ecosystem feel and consistency in codebases (able to follow @TkDodo's caching key suggestions by keeping related keys in an object/functions) 1c) 1d) We'd then be able to pass additional keys to modify the persistence functionality. IE: useForm({
formPersister: useFormPersister({
persistKey: ['myFormKey'],
omitKeys: ['password']
})
}) Persisted State APIs
2a) Mutate const form = useForm({
defaultValues: {/*...*/}
})
const {isRestoring, isRestored} = useFormPersister({
form,
persistKey: ['myFormKey'],
omitKeys: ['password']
}) Which would allow us to reuse the const useFormPersister = ({form, persistKey, omitKeys}) => {
const {state, persister} = getFormPersister({persistKey, omitKeys})
form.persister = persister;
// Mutates `form` state, doesn't return a new instance
mergeForm(form, state)
} 2b) Use the API outlined in #1 to extract from the const form = useForm({
formPersister: useFormPersister({
persistKey: ['myFormKey'],
omitKeys: ['password']
})
})
// Under-the-hood, these fields are part of the FormPersisterAPI.ts file, not FormAPI.ts
const {isRestoring, isRestored} = form.formPersister; Fine-Grained Persistence
3a) useForm({
formPersister: useFormPersister({
persistKey: ['myFormKey'],
omitKeys: ['password'], // Or maybe: (fieldName, fieldValue) => key !== password (?)
// Or
includeKeys: ['name']
})
}) 3b) useForm({
formPersister: useFormPersister({
persistKey: ['myFormKey'],
shouldPersist(fieldName, fieldValue) {
if (fieldName === "password") return false;
return true;
}
})
}) Custom Serializer
4a) Consistency with TanStack Query 4b) Persisting built-in objects like |
…into form-persistence
☁️ Nx Cloud ReportCI is running/has finished running commands for commit 0c24ff2. As they complete they will appear below. Click to see the status, the terminal output, and the build insights. 📂 See all runs for this CI Pipeline Execution ✅ Successfully ran 1 targetSent with 💌 from NxCloud. |
I think just about everything is implemented. Next great effort will come in writing the docs and examples. Would love help on that. Notes:
3 & 4. Totally agreed, so went ahead and added those in, too. |
…into form-persistence
This reverts commit b650bba.
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## main #561 +/- ##
==========================================
- Coverage 88.91% 87.69% -1.23%
==========================================
Files 28 33 +5
Lines 812 894 +82
Branches 187 205 +18
==========================================
+ Hits 722 784 +62
- Misses 83 101 +18
- Partials 7 9 +2 ☔ View full report in Codecov by Sentry. |
Attempt at addresssing #503
This PR includes, the form-persist-core package with tests and the changes to the form-core which make it work. The form-persist-core exports two main things:
class PersisterAPI
and the helperfunction createFormPersister
.The persister is an optional field to the FormApi class, which when passed, triggers restoring and persistence on FormState changes. For persisting to localStorage, it is:
The storage field can also be async, as inspired by the persister in TanStack/query.
Opinions needed for:
API for framework adapters. For React and Solid adapters, I am thinking there should be a global provider for the PersisterAPI, and on then something like
useForm({ persistFormKey: 'myFormKey' })
oruseForm({ formPersister: useFormPersister('myFormKey') })
would be all that is needed. This way the dev can also opt out of persistence for a specific form. Very open to opinions and suggestions. Don't have anything in mind for the Vue version but I don't see why it cant just be the same thing.Persistence state i.e.
isRestored
andisRestoring
are part of the FormState, but I don't really like having that there. Would it be better to have it in the PersisterAPI itself? If it is moved into the persister, we will need some way to pass that state back to the user, which might necessitate something like 'useIsRestoring` or something similar. Again, open to opinions and suggestions.Fine-grained persistence. This might be more of a future thing, but perhaps, there should be a way to opt-out of having certain fields in the persistence. This could certainly just be done by ignoring the form-persistence-core package and passing in a completely custom Persister to the FormApi that can process the FormState as wanted. Just a thought.
Custom serializer. Right now I am just using JSON.parse and JSON.stringify to serial the form state. It should be more than enough considering that state is only strings and numbers. TanStack/query allows their persister to have custom serializers. I don't see the usecases for forms though, although open to hear them, if any. It is very easy to add it in.
To be done:
Am I missing anything else here?