I created a form with formik in order to have form validations. I have used the components Formik, Form, Field form formik and configured them:
import { Formik, Form, Field } from "formik";
import { object, string } from "yup";
import isEmpty from "lodash/isEmpty";
import FormikSelectInput from "../common/FormikSelectInput";
class App extends Component {
render() {
const options = this.props.categories.map(c => {
return { label: c.name, value: c.name };
});
return (
<Formik
validationSchema={object().shape({
category: string().required("Category is required.")
})}
initialValues={this.props.obj}
onSubmit={(values, actions) => {
console.log(values);
}}
render={({ errors, dirty, isSubmitting, setFieldValue }) => (
<Form>
<Field
name="category"
label="Categories"
value={this.props.obj.category.name}
options={options}
component={FormikSelectInput}
/>
<button
type="submit"
className="btn btn-default"
disabled={isSubmitting || !isEmpty(errors) || !dirty}
>
Save
</button>
</Form>
)}
/>
);
}
}
//Prop Types validation
App.propTypes = {
obj: PropTypes.object.isRequired,
categories: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
};
const getElementByID = (items, id) => {
let res = items.filter(l => l.id === id);
return res.length ? res[0] : null; //since filter returns an array we need to check for res.length
};
//Redux connect
const mapStateToProps = ({ objects, categories }, ownProps) => {
let obj = {
id: "",
name: "",
category: { id: "", name: "" }
};
return {
obj: getElementByID(objects, ownProps.match.params.id) || obj,
categories: categories
};
};
export default connect(
mapStateToProps,
{...}
)(App);
And I have a custom component 'FormikSelectInput':
import React, { Component } from "react";
import classnames from "classnames";
import VirtualizedSelect from "react-virtualized-select";
import "react-select/dist/react-select.css";
import "react-virtualized/styles.css";
import "react-virtualized-select/styles.css";
const InputFeedback = ({ children }) => (
<span className="text-danger">{children}</span>
);
const Label = ({ error, children, ...props }) => {
return <label {...props}>{children}</label>;
};
class FormikSelectInput extends Component {
constructor(props) {
super(props);
this.state = { selectValue: this.props.value };
}
render() {
const {
field: { name, ...field }, // { name, value, onChange, onBlur }
form: { touched, errors }, // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
className,
label,
...props
} = this.props;
const error = errors[name];
const touch = touched[name];
const classes = classnames(
"form-group",
{
"animated shake error": !!error
},
className
);
console.log("props", props);
return (
<div className={classes}>
<Label htmlFor={name} error={error}>
{label}
</Label>
<VirtualizedSelect
name={name}
id={name}
className="form-control"
{...field}
{...props}
onChange={(selectValue) => this.setState(() => {
this.props.form.setFieldValue('category',selectValue)
return { selectValue }
})}
value={this.state.selectValue}
/>
{touch && error && <InputFeedback>{error}</InputFeedback>}
</div>
);
}
}
export default FormikSelectInput;
My component is working and I am able to select an option, but why formik together with 'yup' validation showing me an error when I empty the select field.
When I clear my select field I get an ERROR - 'category must be a string
type, but the final value was: null
. If "null" is intended as an empty value be sure to mark the schema as .nullable()
'
My code is based on the this example.
Formik helps you to write the three most annoying parts of building a form: Getting values in and out of form state. Validation and error messages. Handling form submission.
If I want to bootstrap a project with controlled components as fast as possible, then Formik is a great choice. However, it really does not scale well with complex form. React Hook Form was born to solve the performance problem, but well, making it maintainable with external controlled components is a nightmare.
Formik is a React and React Native library that helps you create forms in React "without the tears". You can pair Formik with validation libraries like Yup to make the process even simpler. In this tutorial, you'll learn how creating and validating forms can be simpler in React using Formik and Yup.
React Hook Form isolates input components from the others and prevents re-render of the form for a single input. It avoids this unnecessary re-rendering. So it is a great advantage in terms of the performance compared to Formik which updates every change in every input field.
It looks like the field is expecting the string to be required based on your validationSchema
.
The error helped point me in the right direction. Here's the docs for Yup .nullable()
: https://github.com/jquense/yup#mixednullableisnullable-boolean--true-schema
Try adding .nullable() to the chain of validations.
validationSchema={object().shape({
category: string().required("Category is required.").nullable()
})}
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With