An approach to form validation in React that makes use of ES6 Proxy, by way of @poteto's validated-proxy
library.
react-validated-proxy
exports a single component <Validate>
, which you can use to validate changes to any object.
Note: this library is in alpha and is not ready for production use.
$ npm i react-validated-proxy
import Validate from 'react-validated-proxy';
import { isPresent, hasLength } from './validations';
const user = {
firstName: 'Billy',
lastName: 'Bob',
// ...
};
const Adult = {
firstName: [isPresent(), hasLength({ min: 2 })],
lastName: [isPresent(), hasLength({ min: 2 })],
// ...
};
<Validate model={user} as={Adult}>
{({ model, set, reset, isPristine, hasErrors, flush }) => (
<form onSubmit={flush}>
<input type="text" value={model.firstName} onChange={e => set('firstName', e.target.value)} />
<input type="text" value={model.lastName} onChange={e => set('lastName', e.target.value)} />
<button type="submit" disabled={isPristine || hasErrors}>Save</button>
<button type="button" onClick={reset}>Reset</button>
</form>
)}
</Validate>
See the full code for this example under example/
. You can also clone this repo and run npm install && npm start
to see the example running live.
ES6 Proxies have many cool use cases – one of which is validating changes to objects. You can modify an object as you normally would, and a Proxy
can intercept those modifications to add custom behavior.
In the case of this library, the <Validate>
component accepts a model
object, as well as a map of validations
in the format defined by validated-proxy
. <Validate>
will then wrap your model
in a Proxy, and pass the Proxy to your children
render prop. You can then interact with the Proxy as your model
, but with the added benefit of knowing when and why changes to the model
are invalid. (Specifically, you can easily retrieve error messages from the Proxy.)
react-validated-proxy
owes its existence to validated-proxy
and ember-changeset
by Lauren Tan. It's mostly an experiment in distilling ember-changeset
to its framework-agnostic core.
Pass in a data model that you want to validate, as well as a validation map of validators for your data model. The validation map should be in the format expected by validated-proxy
.
const user = {
firstName: 'Jim',
lastName: 'Bob',
age: 15,
};
const Adult = {
firstName: [isPresent(), hasLength({ min: 2 })],
lastName: [isPresent(), hasLength({ min: 2 })],
age: isNumber({ op: '>=', value: 18 }),
};
<Validate model={user} as={Adult}>
{({ model, set, reset, isPristine, hasErrors, flush }) => (
<form>{/* ... */}</form>
)}
</Validate>
<Validate>
accepts a render prop as its children
, and will pass the wrapped model
(and some helper properties and functions) to the render prop:
interface HelperProps {
model: BufferedProxy
set: <T>(name: string, value: T) => void
reset: () => void
isPristine: boolean
hasErrors: boolean
flush: () => void
}
Jason Tu · GitHub @nucleartide · Twitter @nucleartide