balazsorban44 / use-form Goto Github PK
View Code? Open in Web Editor NEWA React hook ๐ฃ for easy form handling
Home Page: https://npm.im/another-use-form-hook
License: MIT License
A React hook ๐ฃ for easy form handling
Home Page: https://npm.im/another-use-form-hook
License: MIT License
typings
deprecation
warnings for next major releaseREADME
README
Is your feature request related to a problem? Please describe.
When a user fills out a form and submits it, it is often desired that all the input fields are cleared, and the values are set back to initial/default values
Describe the solution you'd like
Such a functionality can be baked into onSubmit
:
1. Provide a simple reset()
function parameter, that takes no arguments, and reuses the useForm#initialState
value.
const form = useForm({
//...
// Whatever is set here is the new value of `form.fields`, after `reset()` is called
// If `initialState` is set async (meaning it's value changed over time), the last value will be used.
initialState: {
email: ""
},
async onSubmit({fields, reset}) {
try {
//... submit your form here
reset() // when the form was submitted successfully, you can call reset() to clear all the input fields
} catch(e) {
// if the submission failed, handle the error here
}
}
})
2. Alternatively, you could take an object as an argument, for partial resetting:
This way, the user can selectively reset certain fields, but it also introduces more complexity, while in most cases, a simple reset would be enough.
const initialState = {
email: "",
name: ""
}
const form = useForm({
//...
initialState,
async onSubmit({fields, handleChange}) {
try {
//... submit your form here
handleChange({ // when the form was submitted successfully, you can call handleChange to change any fields you would like.
...initialState,
email: fields.email // Prevents the e-mail field to be cleared
})
} catch(e) {
// if the submission failed, handle the error here
}
}
})
3. useForm()
could return a state
property, that is set to one of these values:
type FormState = "validationErrors" | "submitPending" | "submitError" | "submitSuccess"
This could replace/accompany useForm()#loading
, as a good practice:
https://kentcdodds.com/blog/stop-using-isloading-booleans
This keeps the useForm()
API clean and lower level, while also solving other potential issues by being able to track the precise state of the form at all times.
For example, useForm comes with a built-in notification handling, which may add unnecessary complexity to the API. With a simple state
property, the user could simply handle notifications themselves.
Describe alternatives you've considered
A workaround with today's API could look like this:
// Option 3. could simplify this, by not having to set the `submitted` state manually.
const initialState = {
email: "",
} // This must either be defined outside of the component or be wrapped in `React.useMemo` to be reuseable in the `useEffect code below`
const [submitted, setSubmitted] = React.useState(false)
const form = useForm({
//...
initialState,
async onSubmit({fields, handleChange}) {
try {
//... submit your form here
setSubmitted(true) // when the form was submitted successfully, set a submitted state
} catch(e) {
// if the submission failed, handle the error here
}
}
})
React.useEffect(() => {
if(submitted) {
handleChange(initialState)
setSubmitted(false)
}
}, [submitted, handleChange, initialState]) // You would only need to add initialState, if it was defined inside the component
UPDATE:
After an internal discussion, I landed on option 3, as it has a real potential to simplify the API by getting rid of notification handling.
Internally, handleChange
and/or handleSubmit
uses fields
(an object, containing all the values of a form), and since they are not deep compared, it leads to unoptimized behavior in those functions. A (temporary) solution for the problem could be similar to use-deep-compare-effect, but it is generally recommended to avoid deep comparisons in hooks. I will probably include a simple JSON.stringify(fields)
kind of solution for now, but I feel that something more elegant is needed in the long run.
I am open to suggestions! ๐
My idea is to introduce a new way to connect inputs to the useForm
hook.
Here is a comparison of the current and the future version:
const form = useForm({
name: "form",
validators: {
email: ({email}) => // Your magical ๐ง email validator
}
})
return (
<>
<label htmlFor="email">
- { form.fields.email.error ? "Invalid" : "" } email
+ { form.errors.email ? "Invalid" : "" } email
</label>
<input
- id="email"
- name="email"
- value={form.fields.email.value}
- onChange={form.handleChange}
+ { ...form.propsFor("email") }
/>
</>
)
As you can see, it could reduce the amount of repetitive code, without losing any of the functionality.
propsFor(name, type, validations)
would take three arguments:
name
: being the only required one.type
: referring to the input types. If not defined, it will be inferred from the name you have given and it will use text
as defaultvalidations
: an array of strings and each of them refers to a function in validators
, that is given when registering the useForm
hook. It has the same purpose as form.handleChange
's second argument.If you want more control, let's say you want a custom event handler for onChange
, you could do it easily like this:
<input
{ ...form.propsFor("email") }
onChange={myCustomHandleChange}
/>
Note the order of the props. By defining onChange
under propsFor
, you will override the built-in version, and will have full control. Don't forget to propagate the actual changes to useForm
inside myCustomHandleChange
though. (For example, you could call form.handleChange(e)
somewhere inside myCustomHandleChange
)
Is your feature request related to a problem? Please describe.
It feels like TypeScript is the de facto type safe method to write JavaScript today. Supporting it that way instead of declaration files feels like the right move.
Describe the solution you'd like
Converting the whole codebase will take some effort. Current feature additions will be stopped to avoid conflicts, but since there are declaration files already available, it should not be such a complicated task. I am considering TSDX for compilation, as I have some experience with it.
Describe alternatives you've considered
When I created this package, I just started learning about TypeScript, and at the time it seemed like a way too big of a commitment to write the whole package that way. Since than I have worked on TS projects enough to have the confidence to make that change.
case 'checkbox': {
const _onChange = (e) => {
// TODO: update useForm
onChange({ [name]: e.target.checked })
}
console.log(value.value)
return (
<FormControlLabel
control={
<Checkbox
checked={value.value}
name={name}
onClick={_onChange}
/>}
label={t(`${name}.label`)}
/>
)
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.