@jbknowledge/react-form v0.2.0
React Form
Let's make forms a little less painful shall we?
<Form
onSubmit={({ values, formValid, resetInputs }) => {
if (formValid) {
makeApiCall(values);
} else {
resetInputs(['password']);
}
}}
>
<Input name="user.firstName" />
<Input name="user.lastName" />
<Input name="email" />
<Input name="password" />
<button type="submit">
Submit
</button>
</Form>Installation
npm install @jbknowledge/react-formReact Native Development
Due to some limitations of react-native, form submit events are only supported by the web version of this package at this time. In addition, you should always import from the native submodule when developing in react-native. For example:
import { Form, withFormHandling } from '@jbknowledge/react-form'; // This will not work for react-native projects
import { Form, withFormHandling } from '@jbknowledge/react-form/native';API
This library exports the following:
withFormHandlingFormValidationError
withFormHandling(Component, onChange)
This HoC will provide Component with 4 props:
value: The current value for the inputsetValue: A callback function which replace the existing form valueerror: The current error message associated with the input, or nullinputProps: An object of meta values which are passed to all inputs within the form
const Input = ({ value, setValue, error, inputProps }) => (
<div className="form-group">
{error && inputProps.displayErrors && <div className="form-error">{error}</div>}
<input
className="form-input"
value={value}
onChange={e => setValue(e.target.value)}
/>
</div>
);
export default withFormHandling(Input);In addition, components wrapped by withFormHandling must be provided a name prop, i.e.
<Input name="password" />Error Handling
By default, react-form does not provide any error handling. The second argument for the HoC withFormHandling or onChange is how you can declare validation rules for your components. onChange is expected to be either a single callback or an array of callbacks and will be called automatically by react-form everytime the value changes. The first arg value will be the next value while props will be all props passed to your wrapped component. This function when called sets the value of error on your behalf. Any error thrown by the onChange callback you provide will automatically be caught and passed to your component via the error prop.
export default withFormHandling(Input, (value) => {
throw new Error(); // props.error will be set to the thrown error
});In the event your component has one or more anticipated errors, you can take advantage of the custom ValidationError provided by react-form as a convenience.
export default withFormHandling(Input, (value) => {
if (isNaN(value)) {
throw new ValidationError('Please enter a number.'); // props.error will be set to the string provided
}
});In addition to value, the onChange callback is also provided all component props. This will allow you to achieve validation similar to the following:
export default withFormHandling(Input, (value, { regex }) => {
if (regex && !value.match(regex)) {
throw new ValidationError('Invalid pattern.')
}
});If you provide an array of callback functions, each will run until an error is thrown.
export default withFormHandling(Input, [
() => throw new ValidationError('Invalid'),
someValidationFunction // never called because the first callback always errors
]);Input Names
All components which are wrapped by withFormHandling are required to define a value for the name prop.
<Input name="password" />This requirement serves two purposes:
- it allows
react-formto uniquely identify inputs for state management - it allows you to define the structure of the resulting form values
name can be anything, however, it is recommended that you mimic your api's schema. For example, with the following schema:
{
"user": {
"name": <string>,
"age": <number>
},
"title": <string>,
}You can define inputs such as the following:
<Form>
<Input name="user.name" />
<Input name="user.age" />
<Input name="title" />
</Form>Form
All components wrapped by withFormHandling must be nested underneath one of react-form's Form components like above. Wrapped inputs, however, do not need to be direct children of the Form object; the following is also a valid example:
<Form>
<div>
<div>
<Input name="password" />
</div>
</div>
</Form>Other than props supported by html's form, you can provide the following props to the Form component:
onSubmit({ formValid, values, resetInputs })
This callback function will be called anytime a submit event is fired within the Form component.
NOTE: this callback is not currently supported for react-native, use the onChange callback instead.
formValid: true or false based on all of the nested inputs' error props.values: All form values; structure is based on the value of nested inputs' name props.resetInputs: A callback function which will allow you to reset one or more inputs back to their default values. See the Resetting Inputs section for more information.
For example, the following form:
<Form>
<Input name="nested.value" />
<Input name="value" />
</Form>could call your provided onSubmit callback with:
{
formValid: false,
values: {
nested: {
value: 'example1',
},
value: 'example2'
},
resetInputs: () => {...}
}onChange({ formValid, values })
This callback function will be called anytime a form value changes.
formValid: true or false based on all of the nested inputs' error props.values: All form values; structure is based on the value of nested inputs' name props.resetInputs: A callback function which will allow you to reset one or more inputs back to their default values. See the Resetting Inputs section for more information.
An example of what this might look like can be seen in the onSubmit section.
inputProps
This is a simple object that passes user defined props directly to the wrapped inputs. For example:
<Form
inputProps={{
displayErrors: false,
}}
>This inputProps block would be passed as is automatically to all inputs wrapped by withFormHandling making the following possible:
const CustomInput = ({ value, error, setValue, inputProps }) => (
<div>
{ error && inputProps.displayErrors && <div>{error}</div>}
<input ... />
</div>
);
export default withFormHandling(CustomInput);NOTE: react-form does not perform any optimization on this prop. Guaranteeing referential equality of inputProps is the responsibility of the user.
Resetting Inputs
In both of the provided Form lifecycle hooks, onChange and onSubmit, you are able to reset the value of one or more inputs back to their default values via the provided resetInputs(patterns) function.
patterns: An array of glob patterns which will be matched with your inputs' names.
Given the following form:
<Form
onChange={() => {...}}
>
<Input name="username" defaultValue="johndoe34" >
<Input name="address.street" >
<Input name="address.city" >
<Input name="address.state" >
<Input name="address.zip" >
</Form>resetInputs(['address.state', 'address.city'])will reset the values ofaddress.stateandaddress.cityback to empty stringsresetInputs(['username'])will reset the value ofusernametojohndoe34resetInputs(['address.*'])will reset the value of all inputs exceptusernameback to empty stringsresetInputs()which is the same asresetInputs(['*'])will reset all inputs back to their default values
Contributors
react-form was built and is maintained by JBKLabs, JBKnowledge Inc's research and development team.
Licensing
This package is licensed under Apache License, Version 2.0. See LICENSE for the full license text.
6 years ago