0

I'm trying to use React Select with useForm and got stuck when submitting form values.

My goal is a multi value react select with a default value and onChange function to do some validations when changing (like limit the number of itens to 3).

I already tried to search the solution in others posts and did make some changes in my code but unfortunately I did not succeed.

Everything seems to work perfectly but when I submit the form, my controller results in undefined value.

import React, {useEffect, useState, useContext} from 'react'
import {useForm, Controller} from 'react-hook-form'
import axios from 'axios';
import Select from 'react-select';
import BeeUtils from '../../../utils/BeeUtils'

export default function EditCategory2({place, goBack}){
   var messageFieldRequired = 'Campo Obrigatório';
    
      const audienceOptions = [
        { value: 'Lésbicas', label: 'Lésbicas' },
        { value: 'Gays', label: 'Gays' },
        { value: 'Bissexuais', label: 'Bissexuais' },
        { value: 'Transexuais', label: 'Transexuais' },
        { value: 'Queer', label: 'Queer' },
        { value: 'Intersexo', label: 'Intersexo' },
        { value: 'Assexual', label: 'Assexual' },
        { value: 'Héteros', label: 'Héteros' },
        { value: 'Todxs', label: 'Todxs' }
      ]

    const handleAudienceSelector = (e) => {
        console.log('OK');    
        console.log(e);
        if(e.length > 3){
                e.pop();
                alert('max of 3 selected');
        }
    }
    
    
    const {register , handleSubmit, errors, setValue, getValues, setError, control} = useForm();

    
    const requestUpdate = async (data) => {
        data.createdBy = place.createdBy;
        data._id = place._id;
        data.recordUpdatedType = 'audience';
        console.log(data);
        return;
    }


    const selectRequired = (e) => {
        console.log(e);
        console.log('OK-2');
        //var error = e.length == 0? messageFieldRequired : '';
        //return error;
    }
    
    const onSubmit = data => {
            console.log(data)
            requestUpdate(data);
        }  
    
        return (
            <div className='cad-form'>
          <form onSubmit={handleSubmit(onSubmit)}> 
          <div className='cad-tit-container'> 
             <span className='cad-titulo'> Edit Here</span>
          </div>
          
          <div className='cad-container'>

            <label htmlFor='test-audience'>Audience</label>  
            <Controller
                    name="test-audience"
                    control={control}
                    rules={{ validate: selectRequired }}
                    render={() => (
                        <Select 
                            defaultValue={[audienceOptions[0], audienceOptions[1]]}
                            isMulti
                            onChange={handleAudienceSelector}
                            placeholder='Select Itens'
                            options={audienceOptions}
                            className="basic-multi-select selectCustom"
                            classNamePrefix="select"
                        />
                        )}
                />
            {errors?.targetAudience && <p>{errors.targetAudience.message}</p>}

          </div>

          <div className='btn-container'>
          <div className='cad-btn'><button onClick={(e) => goBack('initial')} className="btn waves-effect yellow darken-2">Voltar</button></div>
          <div className='cad-btn'><button type='submit' className="btn waves-effect yellow darken-2">Salvar Alterações</button></div>
          </div>
        </form>
        </div>
        )
    }

After some changes (thanks to help of the answer) I tried this code

import React, {useEffect, useState, useContext} from 'react'
import {useForm, Controller} from 'react-hook-form'
import axios from 'axios';
import Select from 'react-select';
import BeeUtils from '../../../utils/BeeUtils'

export default function EditCategory2({place, goBack}){
    var messageFieldRequired = 'Campo Obrigatório';
    
      const audienceOptions = [
        { value: 'Lésbicas', label: 'Lésbicas' },
        { value: 'Gays', label: 'Gays' },
        { value: 'Bissexuais', label: 'Bissexuais' },
        { value: 'Transexuais', label: 'Transexuais' },
        { value: 'Queer', label: 'Queer' },
        { value: 'Intersexo', label: 'Intersexo' },
        { value: 'Assexual', label: 'Assexual' },
        { value: 'Héteros', label: 'Héteros' },
        { value: 'Todxs', label: 'Todxs' }
      ]

    const handleAudienceSelector = (e) => {
        console.log('OK');    
        console.log(e);
        if(e.length > 3){
                e.pop();
                alert('max of 3 selected');
        }
    }
    
    
    const {register , handleSubmit, errors, setValue, getValues, setError, control} = useForm();

    
    const requestUpdate = async (data) => {
        data.createdBy = place.createdBy;
        data._id = place._id;
        data.recordUpdatedType = 'audience';
        console.log(data);
        return;
    }
    
    const onSubmit = data => {
            console.log(data)
            requestUpdate(data);
        }  
    
        return (
            <div className='cad-form'>
          <form onSubmit={handleSubmit(onSubmit)}> 
          <div className='cad-tit-container'> 
             <span className='cad-titulo'> Edit Here</span>
          </div>
          
          <div className='cad-container'>

            <label htmlFor='test-audience'>Audience</label>  
            <Controller
              name="targetAudience"
              control={control}
              defaultValue={[audienceOptions[0], audienceOptions[1]]}
              rules={{ required: messageFieldRequired }}
              render={({ field: { onChange, value } }) => (
                <Select
                  value={value}
                  onChange={onChange}
                  isMulti
                  placeholder="Select Itens"
                  options={audienceOptions}
                  className="basic-multi-select selectCustom"
                  classNamePrefix="select"
                />
              )}
            />

          </div>

          <div className='btn-container'>
          <div className='cad-btn'><button onClick={(e) => goBack('initial')} className="btn waves-effect yellow darken-2">Voltar</button></div>
          <div className='cad-btn'><button type='submit' className="btn waves-effect yellow darken-2">Salvar Alterações</button></div>
          </div>
        </form>
        </div>
        )
    }

But now I got the error: TypeError: Cannot read property 'onChange' of undefined

1 Answer 1

1

The reason why it isn't working is because you forgot to to link the <Controller /> component with the <Select /> component via the value and onChange properties of the render prop function from <Controller />.

<Controller
  name="targetAudience"
  control={control}
  defaultValue={[audienceOptions[0], audienceOptions[1]]}
  rules={{ required: "Campo obrigatório", validate: isOnly3Values }}
  render={({ field: { onChange, value } }) => (
    <Select
      value={value}
      onChange={onChange}
      isMulti
      placeholder="Select Itens"
      options={audienceOptions}
      className="basic-multi-select selectCustom"
      classNamePrefix="select"
    />
  )}
/>

You also don't need to use useState here for handling the error state as RHF already provides this functionality. For setting a field to be required, you can just set the required property of the validation object which can be passed to <Controller /> via the rules prop. Check here for more information about <Controller />. I would suggest to also use the validate function from RHF to check if the user added more than 3 items to your <Select /> and display an error message instead of using an alert.

I made some overall small changes and corrected some minor issues (e.g. the errors object is located in the formState property since v7). Feel free to write a comment if something isn't clear.

Edit React Hook Form - Basic (forked)

Sign up to request clarification or add additional context in comments.

5 Comments

Hi @knoefel thanks for your reply, I did try copying and pasting your code (just removed the "validate" function") and I got the error "TypeError: Cannot read property 'onChange' of undefined". Could you help me to solve this?
I also update the original post with the code I've tried to execute
Are you using react-hook-form with a v6 version?
yes I was using 6.15, sorry about that. I already updated the version to 7.11 Now no errors were showed, but it seems that required message is not working (the form isnt submitted, but the message of required still not appearing. T-T
I was able to show errors message. I was using: const {register , handleSubmit, setValue, getValues, setError, control, errors} = useForm(); changed to: const {register , handleSubmit, setValue, getValues, setError, control, formState: { errors }} = useForm(); now its working fine, thank you!!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.