Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

145
Vistas
Manera correcta de usar el controlador de forma de gancho de reacción con Autocompletar Material-UI

Estoy tratando de usar un componente Material-UI Autocomplete personalizado y conectarlo a react-hook-form .

TLDR: es necesario usar MUI Autocompletar con el controlador de forma de gancho de reacción sin defaultValue

Mi componente Autocomplete personalizado toma un objeto con la estructura {_id:'', name: ''} , muestra el nombre y devuelve el _id cuando se selecciona una opción. El Autocomplete funciona bien.

 <Autocomplete options={options} getOptionLabel={option => option.name} getOptionSelected={(option, value) => option._id === value._id} onChange={(event, newValue, reason) => { handler(name, reason === 'clear' ? null : newValue._id); }} renderInput={params => <TextField {...params} {...inputProps} />} />

Para que funcione con react-hook-form configuré setValues para que sea el controlador de onChange en Autocomplete y registré manualmente el componente en un useEffect de la siguiente manera

 useEffect(() => { register({ name: "country1" }); },[]);

Esto funciona bien, pero me gustaría no tener el gancho useEffect y simplemente hacer uso del registro de alguna manera directamente.

A continuación, traté de usar el componente Controller de react-hook-form para registrar correctamente el campo en el formulario y no usar el gancho useEffect

 <Controller name="country2" as={ <Autocomplete options={options} getOptionLabel={option => option.name} getOptionSelected={(option, value) => option._id === value._id} onChange={(event, newValue, reason) => reason === "clear" ? null : newValue._id } renderInput={params => ( <TextField {...params} label="Country" /> )} /> } control={control} />

Cambié onChange en el componente Autocomplete para devolver el valor directamente, pero parece que no funciona.

Usar inputRef={register} en <TextField/> no me serviría porque quiero guardar el _id y no el name

AQUÍ hay una caja de arena de trabajo con los dos casos. El primero con useEffect y setValue en el Autocomplete que funciona. El segundo mi intento de usar el componente Controller

Cualquier ayuda es apreciada.

LE

Después del comentario de Bill con el sandbox de trabajo de MUI Autocompletar, logré obtener un resultado funcional

 <Controller name="country" as={ <Autocomplete options={options} getOptionLabel={option => option.name} getOptionSelected={(option, value) => option._id === value._id} renderInput={params => <TextField {...params} label="Country" />} /> } onChange={([, { _id }]) => _id} control={control} />

El único problema es que me sale un MUI Error en la consola

Material-UI: un componente está cambiando el estado de valor no controlado de Autocompletar para ser controlado.

Intenté establecer un defaultValue para él, pero aún se comporta así. Además, no me gustaría establecer un valor predeterminado de la matriz de opciones debido al hecho de que estos campos en el formulario no son obligatorios.

El sandbox actualizado AQUÍ

Cualquier ayuda sigue siendo muy apreciada.

over 4 years ago · Santiago Trujillo
4 Respuestas
Responde la pregunta

0

Entonces, arreglé esto. Pero reveló lo que creo que es un error en Autocompletar.

Primero... específicamente para su problema, puede eliminar el MUI Error agregando un valor predeterminado al <Controller> . Pero eso fue solo el comienzo de otra ronda o problemas.

El problema es que a las funciones getOptionLabel , getOptionSelected y onChange a veces se les pasa el valor (es decir, el _id en este caso) y, a veces, se les pasa la estructura de opciones, como era de esperar.

Aquí está el código que finalmente se me ocurrió:

 import React from "react"; import { useForm, Controller } from "react-hook-form"; import { TextField } from "@material-ui/core"; import { Autocomplete } from "@material-ui/lab"; import { Button } from "@material-ui/core"; export default function FormTwo({ options }) { const { register, handleSubmit, control } = useForm(); const getOpObj = option => { if (!option._id) option = options.find(op => op._id === option); return option; }; return ( <form onSubmit={handleSubmit(data => console.log(data))}> <Controller name="country" as={ <Autocomplete options={options} getOptionLabel={option => getOpObj(option).name} getOptionSelected={(option, value) => { return option._id === getOpObj(value)._id; }} renderInput={params => <TextField {...params} label="Country" />} /> } onChange={([, obj]) => getOpObj(obj)._id} control={control} defaultValue={options[0]} /> <Button type="submit">Submit</Button> </form> ); }
over 4 years ago · Santiago Trujillo Denunciar

0

La respuesta aceptada (probablemente) funciona para la versión con errores de Autocompletar. Creo que el error se solucionó algún tiempo después, por lo que la solución se puede simplificar un poco.

Esta es una referencia/codesandbox muy útil cuando se trabaja con react-hook-form y material-ui: https://codesandbox.io/s/react-hook-form-controller-601-j2df5 ?

Desde el enlace anterior, modifiqué el ejemplo de Autocompletar:

 import TextField from '@material-ui/core/TextField'; import Autocomplete from '@material-ui/lab/Autocomplete'; const ControlledAutocomplete = ({ options = [], renderInput, getOptionLabel, onChange: ignored, control, defaultValue, name, renderOption }) => { return ( <Controller render={({ onChange, ...props }) => ( <Autocomplete options={options} getOptionLabel={getOptionLabel} renderOption={renderOption} renderInput={renderInput} onChange={(e, data) => onChange(data)} {...props} /> )} onChange={([, data]) => data} defaultValue={defaultValue} name={name} control={control} /> ); }

Con el uso:

 <ControlledAutocomplete control={control} name="inputName" options={[{ name: 'test' }]} getOptionLabel={(option) => `Option: ${option.name}`} renderInput={(params) => <TextField {...params} label="My label" margin="normal" />} defaultValue={null} />

el control es del valor de retorno de useForm(}

Tenga en cuenta que estoy pasando null como valor defaultValue ya que en mi caso esta entrada no es necesaria. Si deja defaultValue , es posible que obtenga algunos errores de la biblioteca material-ui.

ACTUALIZAR:

Según la pregunta de Steve en los comentarios, así es como represento la entrada, para que verifique si hay errores:

 renderInput={(params) => ( <TextField {...params} label="Field Label" margin="normal" error={errors[fieldName]} /> )}

Donde errors es un objeto de formMethods de react-hook-form :

 const { control, watch, errors, handleSubmit } = formMethods
over 4 years ago · Santiago Trujillo Denunciar

0

En lugar de usar el controlador, con la ayuda de register, setValue de useForm y value, onChange of Autocompletar podemos lograr el mismo resultado.

 const [selectedCaste, setSelectedCaste] = useState([]); const {register, errors, setValue} = useForm(); useEffect(() => { register("caste"); }, [register]); return ( <Autocomplete multiple options={casteList} disableCloseOnSelect value={selectedCaste} onChange={(_, values) => { setSelectedCaste([...values]); setValue("caste", [...values]); }} getOptionLabel={(option) => option} renderOption={(option, { selected }) => ( <React.Fragment> <Checkbox icon={icon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} /> {option} </React.Fragment> )} style={{ width: "100%" }} renderInput={(params) => ( <TextField {...params} id="caste" error={!!errors.caste} helperText={errors.caste?.message} variant="outlined" label="Select caste" placeholder="Caste" /> )} /> );
over 4 years ago · Santiago Trujillo Denunciar

0

import { Button } from "@material-ui/core"; import Autocomplete from "@material-ui/core/Autocomplete"; import { red } from "@material-ui/core/colors"; import Container from "@material-ui/core/Container"; import CssBaseline from "@material-ui/core/CssBaseline"; import { makeStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import AdapterDateFns from "@material-ui/lab/AdapterDateFns"; import LocalizationProvider from "@material-ui/lab/LocalizationProvider"; import React, { useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; export default function App() { const [itemList, setItemList] = useState([]); // const classes = useStyles(); const { control, handleSubmit, setValue, formState: { errors } } = useForm({ mode: "onChange", defaultValues: { item: null } }); const onSubmit = (formInputs) => { console.log("formInputs", formInputs); }; useEffect(() => { setItemList([ { id: 1, name: "item1" }, { id: 2, name: "item2" } ]); setValue("item", { id: 3, name: "item3" }); }, [setValue]); return ( <LocalizationProvider dateAdapter={AdapterDateFns}> <Container component="main" maxWidth="xs"> <CssBaseline /> <form onSubmit={handleSubmit(onSubmit)} noValidate> <Controller control={control} name="item" rules={{ required: true }} render={({ field: { onChange, value } }) => ( <Autocomplete onChange={(event, item) => { onChange(item); }} value={value} options={itemList} getOptionLabel={(item) => (item.name ? item.name : "")} getOptionSelected={(option, value) => value === undefined || value === "" || option.id === value.id } renderInput={(params) => ( <TextField {...params} label="items" margin="normal" variant="outlined" error={!!errors.item} helperText={errors.item && "item required"} required /> )} /> )} /> <button onClick={() => { setValue("item", { id: 1, name: "item1" }); }} > setValue </button> <Button type="submit" fullWidth size="large" variant="contained" color="primary" // className={classes.submit} > submit </Button> </form> </Container> </LocalizationProvider> ); }
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda