I am using the official Semantic UI React components to create a web application. I have a form on my sign up page, which contains an email field, a password field, and a confirm password field.
import {Component} from 'react';
import {Button, Form, Message} from 'semantic-ui-react';
import {signUp} from '../../actions/auth';
class SignUp extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e, {formData}) {
e.preventDefault();
//
// Potentially need to manually validate fields here?
//
// Send a POST request to the server with the formData
this.props.dispatch(signUp(formData)).then(({isAuthenticated}) => {
if (isAuthenticated) {
// Redirect to the home page if the user is authenticated
this.props.router.push('/');
}
}
}
render() {
const {err} = this.props;
return (
<Form onSubmit={this.handleSubmit} error={Boolean(err)}>
<Form.Input label="Email" name="email" type="text"/>
<Form.Input label="Password" name="password" type="password"/>
<Form.Input label="Confirm Password" name="confirmPassword" type="password"/>
{err &&
<Message header="Error" content={err.message} error/>
}
<Button size="huge" type="submit" primary>Sign Up</Button>
</Form>
);
}
}
Now, I am used to the regular Semantic UI library, which has a Form Validation addon. Usually, I would define the rules like so in a separate JavaScript file
$('.ui.form').form({
fields: {
email: {
identifier: 'email',
rules: [{
type: 'empty',
prompt: 'Please enter your email address'
}, {
type: 'regExp',
value: "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
prompt: 'Please enter a valid email address'
}]
},
password: {
identifier: 'password',
rules: [{
type: 'empty',
prompt: 'Please enter your password'
}, {
type: 'minLength[8]',
prompt: 'Your password must be at least {ruleValue} characters'
}]
},
confirmPassword: {
identifier: 'confirmPassword',
rules: [{
type: 'match[password]',
prompt: 'The password you provided does not match'
}]
}
}
});
Is there a similar method using the Semantic UI React components for validating the form? I've searched through the documentation without any success, and there doesn't seem to be examples of validation using this Semantic UI React library.
Do I instead need to validate each field by hand in the handleSubmit
function? What is the best way to fix this problem? Thanks for the help!
We even have a better option, though not provided by semantic-ui-react -> Formik + yup
Formik: helps in managing form state
Yup: helps in the validation of that state
I have the below component which is basically an edit form created using semantic-ui-react.
import React, { Component } from "react";
import { Button, Form, Modal, Message, Divider } from "semantic-ui-react";
import { Formik } from "formik";
import * as yup from "yup";
class EditAboutGrid extends Component {
render() {
const {
userBasic,
editBasicModal,
closeModal
} = this.props;
return (
<Formik
initialValues={{
firstName: userBasic.firstName,
lastName: userBasic.lastName,
bio: userBasic.bio,
}}
validationSchema={yup.object().shape({
firstName: yup
.string()
.required("Name cannot be empty"),
lastName: yup
.string()
.required("Name cannot be empty"),
bio: yup
.string()
.max(1000, "Maximum characters exceed 1000")
.nullable()
})}
onSubmit={(values, actions) => {
//do your stuff here like api calls
}}
render={({
values,
errors,
handleChange,
handleSubmit,
isSubmitting,
dirty,
setFieldValue
}) => (
<Modal open={editBasicModal} size="small">
<Modal.Header>Your basic details</Modal.Header>
<Modal.Content scrolling>
{errors.firstName && <Message error content={errors.firstName} />}
{errors.lastName && <Message error content={errors.lastName} />}
{errors.bio && <Message error content={errors.bio} />}
<Form loading={isSubmitting}>
<Form.Group inline widths="equal">
<Form.Input
required
label="First Name"
fluid
type="text"
name="firstName"
value={values.firstName}
onChange={handleChange}
error={errors.firstName !== undefined}
/>
<Form.Input
required
label="Last Name"
fluid
type="text"
name="lastName"
value={values.lastName}
onChange={handleChange}
error={errors.lastName !== undefined}
/>
</Form.Group>
<Form.TextArea
label="Bio"
type="text"
name="bio"
value={values.bio}
onChange={handleChange}
rows={3}
error={errors.bio !== undefined}
/>
</Form>
</Modal.Content>
<Modal.Actions open={true}>
<Button
onClick={() => (dirty ? closeModal(true) : closeModal(false))}>
Cancel
</Button>
<Button
primary
type="submit"
onClick={handleSubmit}
loading={isSubmitting}
disabled={isSubmitting || !isEmpty(errors) || !dirty}>
Update
</Button>
</Modal.Actions>
</Modal>
)}
/>
);
}
}
And this form is called using:
<EditAboutGrid
editBasicModal={this.state.editBasicModal}
userBasic={this.state.user.basic}
closeModal={this.closeModal}
/>
initialValues
is the place where the things start. Here you pass on the initial/default values to the inputs of your form. values
(in form) will pick data value from this default.
validationSchema
is the place where all validation happens using yup
onSubmit
would be called on the form submission.
Handling form using Formik + yup is very easy. I am loving it.