React Final Form
with yup
by @leocaseiro
Forms in React
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
}
handleInputChange = (event) => {
const { name, target } = event.target;
this.setState({
[name]: value
});
}
...
}
Validate Forms in React
handleInputChange = (e) => {
const { name, value } = e.target;
let errors = this.state.errors;
switch (name) {
case 'email':
errors.email = Regex.email.test(value)
? ''
: 'Email is not valid!';
break;
case 'password':
errors.password = value.length < 8
? 'Password must be 8 characters long!'
: '';
break;
default:
break;
}
this.setState({errors, [name]: value});
}
Show error on blur in React
handleBlur = (e) => {
const { name, value } = e.target;
if (this.state[name] !== value) {
this.setState({ dirty: true });
}
}
render() {
const { dirty, touched } = this.state;
return (
<input
name="username"
onFocus={this.setState({ touched: true })}
onBlur={this.handleBlur} />
{touched && dirty && errors.username
&& <span>errors.username</span>}
);
}
React Form Libraries
17k stars
11k stars
almost 5k stars
by @erikras
by @jaredpalmer
Why React Final Form?
"For several years, I (@erikras) actively maintained the first big form library in the React community, Redux Form. During those years, I learned many lessons, about open source and React, and saw hundreds of forms use cases from around the world. As Redux Form grew in popularity (and bundle size), I received a lot of feedback from the community. React Final Form is my answer the concerns of the community."
React Final Form's Philosphy
React Final Form's Goals
- Strongly Typed
- Modularity / Agnostic
- Minimal Bundle Size
- High Performance
Architecture
React Final Form is a thin React wrapper for Final Form, which is a subscriptions-based form state management library that uses the Observer pattern, so only the components that need updating are re-rendered as the form's state changes.
Getting Started
npm install final-form react-final-form
import { Form, Field } from 'react-final-form'
const MyForm = () => (
<Form
onSubmit={onSubmit}
validate={validate}
render={formProps => (
<form onSubmit={formProps.handleSubmit}>
//...
</form>
)}
/>
)
React Final Form Example
<Form
onSubmit={onSubmit}
validate={validate}
render={props => (
<form onSubmit={props.handleSubmit}>
<Field
name="username"
render={({ input, meta }) => (
<div>
<input {...input} />
{meta.errror && (
<span>{meta.error}</span>
)}
</div>
)}
</Field>
<button type="submit">Submit</button>
</form>
)}
</Form>
- active
- dirty
- dirtyFields
- dirtySinceLastSubmit
- error
- errors
- hasSubmitErrors
- hasValidationErrors
- initialValues
- invalid
- modified
- pristine
- submitError
- submitErrors
- submitFailed
- submitSucceeded
- submitting
- touched
- valid
- validating
- values
- visited
FormApi (props)
- isEqual
- name
- parse
- render
- subscription
- validate
- validateFields
- value
FieldApi (props)
- afterSubmit
- allowNull
- beforeSubmit
- children
- component
- defaultValue
- format
- formatOnBlur
- initialValue
<Field render={({input}) => {
- name
- onBlur
- onChange
- onFocus
- value
- active
- data
- dirty
- dirtySinceLastSubmit
- error
- initial
- invalid
- modified
- pristine
- submitError
- submitFailed
- submitSucceeded
- submitting
- touched
- valid
- validating
- visited
<Field render={({meta}) => {
React Final Form
+
YUP
yup
import { object, string, date } from 'yup'
const validationSchema = {
object().shape({
email: string()
.email()
.required("Required"),
password: string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number."),
dateOfTravel: date().when("fromFuture", {
is: true,
then: date()
.required("What time did you travel from?")
.min(new Date(), "You said you were from the future!")
})
})
}
add yup validationSchema
import { object, string, date } from 'yup'
const validationSchema = {
object().shape({
email: string()
.email()
.required("Required"),
password: string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number."),
dateOfTravel: date().when("fromFuture", {
is: true,
then: date()
.required("What time did you travel from?")
.min(new Date(), "You said you were from the future!")
})
})
}
Field with schema validate
name = 'email'
validateField = (value) => {
const { schema } = this.validationSchema.field[this.name];
try {
schema.validateSync(value);
} catch (e) {
return e.errors && e.errors[0];
}
}
render() {
return (<Field name={this.name} validate={this.validateField}>)
}
Show error message from yup
<Field {...props}
name={name}
validate={this.validateField}
>
{({ input, meta }) => (
<input {...input} />
{meta.touched && meta.error && <span>{meta.error}</span>}
)}
</Field>
Conditional Fields
const Condition = ({ when, is, children }) => (
<Field name={when} subscription={{ value: true }}>
{({ input: { value } }) => is(Number(value)) ? children : null
}
</Field>
);
<Condition when="isFromFuture" is={value => !!value}>
<Field
name="dateOfTravel"
/>
</Condition>
Focus on Error
npm install final-form-focus
import React from 'react'
import { Form, Field } from 'react-final-form'
import createDecorator from 'final-form-focus'
const focusOnErrors = createDecorator()
<Form
decorators={[ focusOnErrors ]
/>
React Final Form with Yup
By Leo Caseiro
React Final Form with Yup
- 2,439