Felipe V
Felipe V

Reputation: 621

React Hook Forms + Material UI Checkboxes

I am having an error when submiting a form build using React Hook Form and material-ui checkboxes components. The number of checkboxes are build from a list from my api:

        <Grid item xs={12}>
          <FormControl
            required
            error={errors.project?.stack ? true : false}
            component='fieldset'>
            <FormLabel component='legend'>Tech Stack</FormLabel>
            <FormGroup>
              <Grid container spacing={1}>
                {techs.map((option, i) => (
                  <Grid item xs={4} key={i}>
                    <FormControlLabel
                      control={
                        <Checkbox
                          id={`stack${i}`}
                          name='project.stack'
                          value={option.id}
                          inputRef={register({required: 'Select project Tech Stack'})}
                        />
                      }
                      label={option.name}
                    />
                  </Grid>
                ))}
              </Grid>
            </FormGroup>
            <FormHelperText>{errors.project?.stack}</FormHelperText>
          </FormControl>
        </Grid>

When the form is submited I got the following error ( several times , 1 for each checkbox rendered ) :

Uncaught (in promise) Error: Objects are not valid as a React child (found: object with keys {type, message, ref}). If you meant to render a collection of children, use an array instead.

I don't understand this error. The message apparently says it is a rendering issue, but the component renders fine. The problems happens on submit. Any advices ?

Thank you

Upvotes: 28

Views: 59338

Answers (6)

DINA TAKLIT
DINA TAKLIT

Reputation: 8418

Here is the simplest way to do it using Controller

<Box>
<Controller
  control={control}
  name={`${dimension.id}-${dimension.name}`}
  defaultValue={false}
  render={({ field: { onChange, value } }) => (
    <FormControlLabel
      control={
        <Checkbox checked={value} onChange={onChange} />
      }
    />
  )}
/>
</Box>

Upvotes: 3

Juan Garc&#237;a
Juan Garc&#237;a

Reputation: 1898

UPDATE: if you are using RHF >= 7, you should use props.field to call props.field.value and props.field.onChange.


You can use the default Checkbox Controller:

<FormControlLabel
    control={
      <Controller
        name={name}
        control={control}
        render={({ field: props }) => (
          <Checkbox
            {...props}
            checked={props.value}
            onChange={(e) => props.onChange(e.target.checked)}
          />
        )}
      />
    }
    label={label}
  />

I used the controller example from RHF but had to add checked={props.value}: https://github.com/react-hook-form/react-hook-form/blob/master/app/src/controller.tsx

Upvotes: 40

Moises Huaringa
Moises Huaringa

Reputation: 41

Material UI + React Hook Form + Yup . Example page: https://moiseshp.github.io/landing-forms/

  • Without extra dependences
  • Show and hide error messages
// import { yupResolver } from '@hookform/resolvers/yup'
// import * as yup from 'yup'

const allTopics = [
  'React JS',
  'Vue JS',
  'Angular'
]

const defaultValues = {
  topics: []
}

const validationScheme = yup.object({
  topics: yup.array().min(1),
})

const MyForm = () => {
  const resolver = yupResolver(validationScheme)

  const {
    control,
    formState: { errors },
    handleSubmit
  } = useForm({
    mode: 'onChange',
    defaultValues,
    resolver
  })

  const customSubmit = (data) => alert(JSON.stringify(data))

  return (
    <form onSubmit={handleSubmit(customSubmit)}>
      <FormControl component="fieldset" error={!!errors?.topics}>
        <FormLabel component="legend">Topics</FormLabel>
        <FormGroup row>
          <Controller
            name="topics"
            control={control}
            render={({ field }) => (
              allTopics.map(item => (
                <FormControlLabel
                  {...field}
                  key={item}
                  label={item}
                  control={(
                    <Checkbox
                      onChange={() => {
                        if (!field.value.includes(item)) {
                          field.onChange([...field.value, item])
                          return
                        }
                        const newTopics = field.value.filter(topic => topic !== item)
                        field.onChange(newTopics)
                      }}
                    />
                  )}
                />
              ))
            )}
          />
        </FormGroup>
        <FormHelperText>{errors?.topics?.message}</FormHelperText>
      </FormControl>
    </form>
  )
}

export default MyForm

Upvotes: 1

Roman Mahotskyi
Roman Mahotskyi

Reputation: 6685

If someone struggle to achieve multiselect checkbox with React material-ui and react-hook-form you can check my codesandbox example

Also, there is a code example provided by react-hook-form in their documentation under useController chapter (don't forget to switch to the checkboxes tab).

enter image description here

Upvotes: 10

andoni vianez
andoni vianez

Reputation: 67

Any of that examples works, I´m using this one:

const checboxArray = [{
    name: '1h',
    label: '1 hora'
  },
  {
    name: '12h',
    label: '12 horas'
  },
  {
    name: '24h',
    label: '24 horas'
  },
  {
    name: '3d',
    label: '3 dias'
  },
]; 


//This inside render function:
{
  checboxArray.map((checboxItem) => ( 
  <Controller name = {
      checboxItem.name
    }
    control = {
      control
    }
    key = {
      checboxItem.name
    }
    rules = {
      {
        required: true
      }
    }
    render = {
      ({
        field: {
          onChange,
          value
        }
      }) =>
      <
      FormControlLabel
      control = { <Checkbox
        checked = {!!value
        }
        onChange = {
          (event, item) => {
            onChange(item);
          }
        }
        name = {
          checboxItem.name
        }
        color = "primary" /
        >
      }
      label = {
        checboxItem.label
      }
      />
    }
    />
  ))
}

Upvotes: 1

Felipe V
Felipe V

Reputation: 621

I managed to make it work without using Controller. The props should be inside the FormControlLabel and not inside Checkbox

                <Grid item xs={4} key={i}>
                    <FormControlLabel
                      value={option.id}
                      control={<Checkbox />}
                      label={option.name}
                      name={`techStack[${option.id}]`}
                      inputRef={register}
                    />
                  </Grid>
                ))}

Upvotes: 11

Related Questions