React Forms

From bibbleWiki
Jump to navigation Jump to search

Introduction

  • Controlled Forms
  • Uncontrolled Forms
  • Using Formik Library
  • Validation
  • Creating reusable custom form elements
  • Uncontrolled forms using React
  • React Hook Form to create uncontrolled forms

Controlled forms

In react we can pass state management to the react component. This is what a controlled form is. It's advantages are

  • Instant Feedback
  • Disable controls dynamically
  • Formats the input data e.g. dates 25-03-2001

Example using UseState

  const [password, setPassword] = useState("");
...
      <Form onSubmit={handleSubmit} className="row g-3 needs-validation">
        <div>
          <div className="col-md-4">
            <Form.Group size="lg" controlId="password">
              <Form.Label>Password</Form.Label>
              <Form.Control
                type="password"
                value={password}
                onChange={(e) => onPasswordChange(e)}
              />
              <div className="invalid-feedback">{passwordError}</div>
              <div className="valid-feedback">Password looks good!</div>
            </Form.Group>
          </div>
        </div>
        <div>
          <div className="col-12">
            <Button
              type="submit"
              className="btn btn-primary"
              disabled={isSubmitting || !formValid}
            >{`${isSubmitting ? "Logging In" : "Login"}`}</Button>
          </div>
        </div>
      </Form>
...

Using React Components

import React from "react";

class EmailForm extends React.Component {
    constructor(props) {
        super(props);
    }
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
    
    handleChange(event) {
        this.setState({value: event.target.value});
    }
    
    render() {
        return (
            <form>
                <input type="email" value={this.state.value} onChange={this.handleChange} />
            </form>
        );
    }
}

Uncontrolled Forms

Uncontrolled forms are when the DOM maintains the states and a reference is stored to it in react.

Using Formik Library

Advantages

This is what is suggests.

  • Reduces Verbosity
  • Reduces code for state and callbacks
  • Reduces errors
  • Tracks values, errors and visited fields
  • Hooks up appropriate callback functions
  • Helpers for sync and async validation and showing errors
  • Sensible defaults

Components of Formik

Here are the components which make up a Formik form. The first being the component responsible for controlling the form

  • Formik
  • Form
  • Field
  • ErrorMessage

Internally Formik maintains three maps.

Formik Using Components

This is the example with components. This now been re-implemented using hooks. It does use styled components around the controls which I personally found to be a bit hard to debug. <syntaxhighlighting lang="js"> import React from "react"; import styled from "styled-components"; import { Formik, Field, Form, ErrorMessage } from "formik";

const SigninForm = styled(Form)`

 display: flex;
 flex-direction: column;
 padding: 30px;
 border: 1px solid black;

`;

const Container = styled.div`

 display: flex;
 flex-direction: column;
 flex: 1;
 height: 100%;
 align-items: center;

`;

const ContentContainer = styled.div`

 display: flex;
 flex-direction: column;
 width: 600px;
 margin-top: 50px;

`;

const Title = styled.h1`

 white-space: pre-line;

`;

const Label = styled.label`

 margin-top: 20px;
 font-size: 24px;

`;

const EmailField = styled(Field)`

 height: 40px;
 font-size: 24px;

`;

const ErrorLabel = styled.div`

 color: red;
 font-size: 26px;

`;

const PasswordField = styled(Field)`

 height: 40px;
 font-size: 24px;

`;

const CheckboxContainer = styled.div`

 display: flex;
 height: 50px;
 align-items: center;

`;

const RememberMeCheckboxField = styled(Field)`

 margin-top: 10px;

`;

const CheckboxLabel = styled(Label)`

 margin-top: 7px;
 margin-left: 10px;

`;

class LoginFormik extends React.Component {

 constructor(props) {
   super(props);
   this.handleSubmit = LoginFormik.handleSubmit.bind(this);
   this.handleValidation = LoginFormik.handleValidation.bind(this);
 }
 static handleSubmit(values) {
   return new Promise((resolve) => {
     setTimeout(() => {
       resolve();
       // eslint-disable-next-line no-alert
       alert(JSON.stringify(values));
     }, 5000);
   });
 }
 static handleValidation(values) {
   const errors = {};
   if (!values.email) {
     errors.email = "Email cannot be empty";
   }
   if (!values.password) {
     errors.password = "Password cannot be empty";
   } else if (values.password.length < 8) {
     errors.password = "Password must be at least 8 characters";
   }
   return errors;
 }
 render() {
   return (
     <Container>
       <ContentContainer>
         <Title>Signin Form</Title>
         <Formik
           initialValues=Template:Email: "", password: "", rememberMe: false
           onSumbit={this.handleSumbit}
           validate={this.handleValidation}
         >
           {() => (
             <SigninForm>
               <Label>Email</Label>
               <EmailField name="email" type="email" />
               <ErrorMessage name="email">
                 {(error) => <ErrorLabel>{error}</ErrorLabel>}
               </ErrorMessage>
               <Label>Password</Label>
               <PasswordField name="password" type="password" />
               <ErrorMessage name="password">
                 {(error) => <ErrorLabel>{error}</ErrorLabel>}
               </ErrorMessage>
               <CheckboxContainer>
                 <RememberMeCheckboxField type="checkbox" name="rememberMe" />
                 <CheckboxLabel>Remember Me</CheckboxLabel>
               </CheckboxContainer>
             </SigninForm>
           )}
         </Formik>
       </ContentContainer>
     </Container>
   );
 }

} export default LoginFormik; </syntaxhighlighting>