ErichBSchulz
ErichBSchulz

Reputation: 15659

How to get `react-bootstrap` and `react-hook-form` to play nice?

I am using these two nice react form libraries (together with axios):

There doesn't seem to be a definitive reference to getting the two to play nice? What is the basic recipe?

This question and this issue partly address the point but its all a bit occult.

(I've tried to answer this question myself below but please feel free to improve - especially if it demonstrated better use of these libraries working togethether)

Upvotes: 11

Views: 10143

Answers (1)

ErichBSchulz
ErichBSchulz

Reputation: 15659

This example seems operational:

  1. 3 fields and a button
  2. error display
  3. onSubmit handler including form locking and a spinner

but it's just starting point!

Todo:

  • client side validation using react-hook-form
  • prettier react-bootstrap styling (but you have the full power of react-bootstrap so knock yourself out!)
import React from "react"                                                                            
import {Form, Button, Card, Container, Row, Col, } from 'react-bootstrap'                            
import Server from "../Server.js"                                                                    
import { JSONDisplayer } from "./Widgets"                                                            
import { useHistory } from "react-router-dom"                                                        
import { useForm, Controller } from 'react-hook-form'                                                
import {display_errors} from '../Utilities.js'                                                       
                                                                                                     
function Signup() {                                                                                  
                                                                                                     
  const history = useHistory()                                                                       
  const {setError, handleSubmit, control, reset, formState: {errors}, getValues                      
    } = useForm()                                                                                    
                                                                                                     
  const onSubmit = (data) => {                                                                       
    console.log('data', data)                                                                        
    return Server.post('/user/create/', data)                                                        
    .then(result => {                                                                                
      console.log('login result', result)                                                            
      history.push("/login")                                                                         
    })                                                                                               
    .catch(error => {display_errors(error, getValues, setError)})                                    
  }                                                                                                  
                                                                                                     
  return (                                                                                           
    <Container> <Row> <Col>                                                                          
    <Card><Card.Header>Create a new user</Card.Header><Card.Body>                                    
    <Form onSubmit={handleSubmit(onSubmit)} onReset={reset} >                                        
        <Form.Group className="mb-3" controlId="formUsername">                                       
          <Form.Label>User name</Form.Label>                                                         
            <Controller control={control} name="username"                                            
              defaultValue=""                                                                        
              render={({ field: { onChange, onBlur, value, ref } }) => (                             
                <Form.Control onChange={onChange} value={value} ref={ref}                            
                isInvalid={errors.username}                                                          
                placeholder="Enter user name" />)} />                                                
          <Form.Text className="text-muted">Login name</Form.Text>                                   
          <Form.Control.Feedback type="invalid">                                                     
            {errors.username?.message}                                                               
          </Form.Control.Feedback>                                                                   
        </Form.Group>                                                                                
                                                                                                     
        <Form.Group className="mb-3" controlId="formEmail">                                          
          <Form.Label>Email</Form.Label>                                                             
            <Controller control={control} name="email"                                               
              defaultValue=""                                                                        
              render={({field: {onChange, onBlur, value, ref}}) => (                                 
                <Form.Control onChange={onChange} value={value} ref={ref} type="email"               
                isInvalid={errors.email}                                                             
                placeholder="Enter email" />)} />                                                    
          <Form.Text className="text-muted">We need a valid email address.</Form.Text>               
          <Form.Control.Feedback type="invalid">                                                     
            {errors.email?.message}                                                                  
          </Form.Control.Feedback>                                                                   
        </Form.Group>                                                                                
                                                                                                     
        <Form.Group className="mb-3" controlId="password">                                           
          <Form.Label>Password</Form.Label>                                                          
            <Controller control={control} name="password"                                            
              defaultValue=""                                                                        
              render={({ field: { onChange, onBlur, value, ref } }) => (                             
                <Form.Control                                                                        
                onChange={onChange} value={value} ref={ref} type="password"                          
                isInvalid={errors.password}                                                          
                placeholder="Enter password" />                                                      
              )} />                                                                                  
          <Form.Text className="text-muted">Don't forget it!!</Form.Text>                            
          <Form.Control.Feedback type="invalid">                                                     
            {errors.password?.message}                                                               
          </Form.Control.Feedback>                                                                   
        </Form.Group>                                                                                
        <Controller control={control}                                                                
          render={({ field: { ref }, formState }) => (                                               
            <Button type="submit" disabled={formState.isSubmitting}                                  
               className="btn btn-primary">                                                          
               {formState.isSubmitting && <span className="spinner-border spinner-border-sm mr-1" />}
               Save                                                                                  
            </Button>                                                                                
          )} />                                                                                      
    </Form></Card.Body></Card>                                                                       
    </Col> </Row> </Container>                                                                       
    )                                                                                                
                                                                                                     
}                                                                                                    
                                                                                                     
export default Signup                                                                                

Generic axios -> react-hook-form error transcriber function:

// transcibe axios errors to react-hook-form
function display_errors(error, getValues, setError) {
  const errs = error.response.data || []
  var got_a_useful_message = false
  // loop over all the fields and set error:  
  for (var field of Object.keys(getValues())) {
    if (errs[field]) {
      got_a_useful_message = true
      setError(field, {
        type: "server",        
        message: errs[field].join(' | ')})
    }
  }
  if (!got_a_useful_message) {
    alert('something has gone wrong')
  }
}

export {display_errors}


Upvotes: 11

Related Questions