Material-ui: Trabajando con react-hook-form

Creado en 8 nov. 2019  ·  40Comentarios  ·  Fuente: mui-org/material-ui

Estoy tratando de hacer un formulario simple con react-hook-form y material-ui . Me gustaría poder:

  1. enviar / validar un formulario
  2. restablecer el formulario correctamente
  3. cargar datos correctamente

Lo sentimos, búsqueda de problemas erróneos, parece un duplicado de https://github.com/mui-org/material-ui/issues/17018.

  • [x] El problema está presente en la última versión.
  • [x] He buscado las ediciones de este repositorio y creo que esto no es un duplicado.

Comportamiento actual 😯

El primer paso funciona correctamente.
La función de reinicio borra el valor, pero el estado de material-ui TextField parece permanecer en "relleno" y los estilos no coinciden con los datos borrados.
La función de reinicio con valores iniciales establece correctamente el valor, pero el comportamiento es el mismo que con el reinicio (bueno, lo contrario en este caso), los datos se cargan pero el estado interno del TextField no se "llena".

Comportamiento esperado 🤔

La entrada de material-ui debe actualizar su estado interno cuando los datos se cargan / borran

Pasos para reproducir 🕹

Puede probar los tres botones de este CodePen:
https://codesandbox.io/s/material-demo-ywutu

  1. Enviar: funciona correctamente validando los datos.
  2. Se restablece correctamente, pero el estado de TextFields no está vacío.
  3. Carga datos correctamente pero el estado de TextFields no se completa.

Presenté un problema en el proyecto react-hook-form pero el propietario me dijo que abriera uno aquí también, así que aquí estamos :)

enhancement external dependency

Comentario más útil

He añadido la etiqueta waiting for users upvotes . Estoy cerrando el tema porque no estamos seguros de que la gente esté buscando ese apoyo. Así que, por favor, vote a favor de este problema si es así. Daremos prioridad a nuestro esfuerzo en función del número de votos a favor.

https://npm-stat.com/charts.html?package=formik&package=react-hook-form&package=react-final-form

Todos 40 comentarios

He añadido la etiqueta waiting for users upvotes . Estoy cerrando el tema porque no estamos seguros de que la gente esté buscando ese apoyo. Así que, por favor, vote a favor de este problema si es así. Daremos prioridad a nuestro esfuerzo en función del número de votos a favor.

https://npm-stat.com/charts.html?package=formik&package=react-hook-form&package=react-final-form

muy necesario: rezar :: rezar :: rezar: ¿alguna solución?

muy necesario!

Definitivamente necesario.

¿Alguna idea de cuál sería la solución?

No estoy seguro de algo específico, pero sé que comencé a usar ambas bibliotecas y realmente me gustaría ver integraciones más estrechas entre las dos. React Hook Form y Material UI son geniales juntos. Su soporte para TypeScript también es bueno.

Hola @oliviertassinari gracias por echarle un vistazo. ¡Parece que MUI TextField está funcionando mejor con la API de entrada nativa ahora! Eso es muy agradable. Solíamos tener el texto del marcador de posición superpuesto en la parte superior del texto cuando se invoca e.target.value = 'xxx' . 👍

Screen Shot 2019-11-20 at 10 06 26 am

https://codesandbox.io/s/react-hook-form-conditional-fields-delete-1frsm
En el ejemplo anterior, <Switch /> no se reinició después de que se invocó la API de reset .

Sería realmente bueno si pudiéramos tener todos los componentes relacionados con el formulario para admitir la API de entrada de formulario nativo (establecer y restablecer el valor a través de la referencia de entrada) Entiendo que es un gran trabajo y admitir una pequeña biblioteca como react-hook-form es algo a considerar (tal vez hasta que la lib se vuelva más popular ❤️)

nuevamente, aprecio su tiempo y esfuerzo para investigar este problema (mantener un proyecto de código abierto ENORME como MUI es una locura para mí y está haciendo un trabajo increíble para la comunidad React). Además de eso, avíseme si puedo trabajar en algo para trabajar con MUI también.

Salud
Factura

@ bluebill1049 Gracias por mirarlo. La biblioteca parece tener una buena tracción, pero todavía está muy por detrás de formik. ¿El restablecimiento del interruptor es el único problema que tenemos?

gracias, @oliviertassinari por reabrir y analizar este problema. 🙏 sí, tienes razón react-hook-form todavía es un chico nuevo en la ciudad y no tienes que actuar si te gustaría esperar un poco más para ver si hay más usuarios adoptando react-hook-form , que Creo que es totalmente razonable (incluso aunque dentro de mi corazón estoy desesperado por querer que funcione con MUI, hahaha sido egoísta😼). Mientras tanto, crearé una tabla de entradas que sea compatible con react-hook-form fuera de la caja (tal vez incluso con un codeandbox también). La publicaré aquí también.

Si las cosas funcionan bien con react-hook-form y el uso es cada vez mayor, tal vez podamos considerar trabajar con la API de entrada nativa (que es lo que el uso de react hook form detrás de escena) sería genial obtener input , select , radio y checkbox funcionan ya que son el uso principal del formulario.

FYI @oliviertassinari Estoy trabajando en algo para cerrar la brecha entre MUI y react-hook-form. https://github.com/react-hook-form/react-hook-form-input

También enfrenta problemas con el restablecimiento y la carga de datos predeterminados. Por favor, investigue este problema. O al menos proporcionar una solución por ahora.

Hola @raikusy, por favor, mira el enlace que he publicado arriba, creo que te ayudará. A largo plazo, sería genial que el componente MUI admita la forma nativa de api 'reset' y actualice el valor a través del componente 'ref', pero este es un gran precio de trabajo que estoy seguro de que MUI tiene muchas características e ideas alineadas que son más importantes. Tal como discutimos anteriormente, hasta que el formulario de gancho de reacción se convierta en la biblioteca principal o se vuelva popular, MUI comenzará a investigar para encontrar soluciones. Espero que esto tenga sentido :) gracias por usar el formulario de gancho de reacción también ❤️🤩🤟🏻

Para su información, ese componente contenedor todavía permitirá que su formulario tenga 0 re-renderizado. Porque la actualización del estado de entrada está aislada dentro del componente contenedor.

Gracias @ bluebill1049, esto se ve genial. Tengo una condición en la que los campos de formulario tendrán un valor predeterminado cuando los datos se transfieran desde los accesorios. Entonces, ¿el componente TextField también funcionará con la solución anterior? También estaba buscando un mejor ejemplo de cómo pasar valores predeterminados con accesorios al formulario. En algún momento, los accesorios pueden provenir de una llamada a la API después de que el formulario ya se haya montado.

@raikusy , debería poder usar la API reset / setValue con el componente contenedor.
restablecer: para el formulario completo -> https://react-hook-form.com/api#setValue
setValue: para individuo -> https://react-hook-form.com/api#reset

No puedo hacer que <Slider /> funcione con RHF.

Usándolo como:

      <FormControl fullWidth component="fieldset" margin="normal">
        <FormLabel component="legend">Palavras</FormLabel>
        <RHFInput
          as={<Slider min={100} max={1200} step={100} valueLabelDisplay="auto" marks={marks} />}
          type="input"
          name="words"
          register={register}
          setValue={setValue}
        />
      </FormControl>

Obtuve el siguiente error:

Warning: Failed prop type: Invalid prop `value` supplied to `ForwardRef(Slider)`.
    in ForwardRef(Slider) (created by WithStyles(ForwardRef(Slider)))
    in WithStyles(ForwardRef(Slider)) (created by SetupAccountForm)
    in Unknown (created by SetupAccountForm)
    in fieldset (created by ForwardRef(FormControl))
    in ForwardRef(FormControl) (created by WithStyles(ForwardRef(FormControl)))
    in WithStyles(ForwardRef(FormControl)) (created by SetupAccountForm)
    in form (created by SetupAccountForm)
    in SetupAccountForm (created by SetupAccountPage)
    in div (created by ForwardRef(CardContent))
    in ForwardRef(CardContent) (created by WithStyles(ForwardRef(CardContent)))
    in WithStyles(ForwardRef(CardContent)) (created by SetupAccountPage)
    in div (created by ForwardRef(Paper))
    in ForwardRef(Paper) (created by WithStyles(ForwardRef(Paper)))
    in WithStyles(ForwardRef(Paper)) (created by ForwardRef(Card))
    in ForwardRef(Card) (created by WithStyles(ForwardRef(Card)))
    in WithStyles(ForwardRef(Card)) (created by SetupAccountPage)
    in div (created by ForwardRef(Grid))
    in ForwardRef(Grid) (created by WithStyles(ForwardRef(Grid)))
    in WithStyles(ForwardRef(Grid)) (created by Layout)
    in Layout (created by SetupAccountPage)
    in SetupAccountPage (created by App)
    in Route (created by App)
    in Switch (created by App)
    in Router (created by HashRouter)
    in HashRouter (created by App)
    in App (created by Root)
    in div (created by ForwardRef(Container))
    in ForwardRef(Container) (created by WithStyles(ForwardRef(Container)))
    in WithStyles(ForwardRef(Container)) (created by Root)
    in div (created by Styled(MuiBox))
    in Styled(MuiBox) (created by Root)
    in Provider (created by Root)
    in Root Button.js:233:15

@hbarcelos parece que el control deslizante no admite accesorios de valor :( Voy a investigar un poco al respecto. Mientras tanto, es posible que tenga que usar un registro personalizado, que se registra en useEffect

Muchas gracias @ bluebill1049

Terminé haciendo algo como esto:

import React, { useEffect, useCallback, useState, useMemo } from 'react';
import t from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/core/styles';
import Box from '@material-ui/core/Box';
import Slider from '@material-ui/core/Slider';

const useStyles = makeStyles(theme => ({
  sliderWrapper: {},
  sliderLabel: {
    marginTop: theme.spacing(1),
    marginBottom: theme.spacing(0.5),
    color: theme.palette.primary.main,
  },
}));

function CustomSlider({
  register,
  unregister,
  setValue,
  name,
  rules,
  defaultValue,
  valueLabelAs,
  formatLabel,
  ...rest
}) {
  const cl = useStyles();

  const [currentValue, setCurrentValue] = useState(defaultValue);

  useEffect(() => {
    register({ name });
    return () => unregister(name);
  }, [defaultValue, name, register, setValue, unregister]);

  const valueLabel = useMemo(() => {
    if (!valueLabelAs) {
      return null;
    }

    return React.cloneElement(
      valueLabelAs,
      { className: clsx(valueLabelAs.props.className, cl.sliderLabel) },
      formatLabel(currentValue)
    );
  }, [cl.sliderLabel, currentValue, formatLabel, valueLabelAs]);

  const handleChange = useCallback(
    (_, value) => {
      setValue(name, value);
      setCurrentValue(value);
    },
    [name, setValue]
  );

  return (
    <React.Fragment>
      {valueLabel}
      <Box className={cl.sliderWrapper}>
        <Slider {...rest} onChange={handleChange} defaultValue={defaultValue} />
      </Box>
    </React.Fragment>
  );
}

CustomSlider.defaultProps = {
  rules: {},
  defaultValue: '',
  valueLabelAs: null,
  formatLabel: v => v,
};

CustomSlider.propTypes = {
  register: t.func.isRequired,
  unregister: t.func.isRequired,
  setValue: t.func.isRequired,
  name: t.string.isRequired,
  rules: t.object,
  defaultValue: t.oneOfType([t.number, t.string]),
  valueLabelAs: t.node,
  formatLabel: t.func,
};

export default CustomSlider;

Funciona como se esperaba.

Muy necesario esto también

A largo plazo, sería genial que el componente MUI admita la forma nativa api 'reset' y actualice el valor a través del componente 'ref'.

@ bluebill1049 ¿No es esto un problema con React o react-hook-form en sí? ¿Cómo se supone que un desarrollador "reaccionará" a un cambio de estado de entrada con react-hook-form?
Digamos que soy un desarrollador de React que crea una entrada personalizada y quiero diseñar el elemento de manera diferente cuando está lleno / vacío, ¿cómo debo implementar esto? Parece que nunca se dispara ningún evento de cambio.

¿Ha considerado activar un evento de cambio cuando su biblioteca cambia un valor de entrada "fuera" del modelo declarativo de React? ¿Como se hace en @ test-library / react?

Esto permitiría el soporte de componentes Material-UI que se basan en elementos de entrada nativos, para los demás, como el Control deslizante, se necesitaría un contenedor personalizado. El control deslizante tiene una propuesta de valor, pero la firma de onChange es diferente de una entrada nativa. Creo que sería genial ver una biblioteca de integración como la que tenemos para las otras bibliotecas de formularios: # 15585.


Me preguntaba por qué este problema recibió tantos votos a favor, creo que lo he descubierto 🙃:

Capture d’écran 2019-12-07 à 20 41 31
https://react-hook-form.com/advanced-usage#ControlledmixedwithUncontrolledComponents

hola @oliviertassinari , gracias por mirar más de cerca este tema nuevamente 👍

Digamos que soy un desarrollador de React que crea una entrada personalizada y quiero diseñar el elemento de manera diferente cuando está lleno / vacío, ¿cómo debo implementar esto? Parece que nunca se dispara ningún evento de cambio.

Buscaría un selector de CSS para soluciones en mi propio proyecto que utiliza entradas nativas, por ejemplo: seleccionar un elemento tiene un valor vacío y mostrar un estilo. Una alternativa, usaría react-hook-form watch API para detectar un valor vacío y pasarlo como prop (con mi componente de entrada envuelto).

¿Ha considerado activar un evento de cambio cuando su biblioteca cambia un valor de entrada "fuera" del modelo declarativo de React? ¿Como se hace en @ test-library / react?

Sí, prácticamente lo estamos haciendo por debajo de react-hook-form-input . 😄

Creo en los componentes no controlados para la construcción de formas después de muchos años de construcción de formas controladas, realmente hace las cosas mucho más fáciles. Puede que no resuelva todos los casos extremos (si trabajas en Facebook LOL), pero ciertamente hace que mi vida laboral y la de los que me rodean sean más fáciles cuando se trata de crear formularios. Las entradas HTML tienen estado en sí mismas y me encantaría incluirlas en esta biblioteca (sin decir que sea correcto o incorrecto, sino una solución alternativa).

Me encanta crear la aplicación React, y es por eso que crear muchos paquetes a su alrededor. Entiendo que React incluye componentes controlados. Sin embargo, react-hook-form no está bloqueando a los desarrolladores para que no construyan controlados por formularios, porque aún puede personalizar register en useEffect .

Conclusión:

Creo que podemos cerrar este problema y eliminaré el enlace de mi sitio web relacionado con este problema. Además de eso, ¿podría actualizar esta página para incluir react-hook-form-input ?

https://material-ui.com/components/text-fields/#complementary -projects

Sí, prácticamente lo estamos haciendo bajo react-hook-form-input.

@ bluebill1049 Parece el enfoque opuesto a mi sugerencia. Entiendo lo siguiente:

  • reaccionar-forma-gancho:

    1. Realiza un seguimiento de los nodos DOM de entrada. Cuando necesita cambiar el valor, lo hace input.value = 'x' . Esto es problemático para React, ya que no tiene forma de saber que el valor de entrada ha cambiado. Por ejemplo, no se activa ningún evento de cambio .

    2. Debido a que react-hook-form necesita escuchar los cambios en el valor de entrada, establece un detector de eventos de "entrada" en la entrada . Esto es problemático para su biblioteca ya que los cambios de React no desencadenan ningún evento cuando el valor cambia de una entrada controlada .

  • react-hook-form-input: la biblioteca controla la entrada para evitar las dos limitaciones anteriores de react-hook-form (i y ii).

Dado que 1. es muy poco probable que React funcione bien para admitir el enfoque react-hook-form y 2. que react-hook-form no funciona fuera de la caja con entradas controladas y pseudo-incontroladas (las que cambian el valor predeterminado y los que solo escuchan onChange), propondría que:

  1. react-hook-form parchea el problema controlado y pseudo incontrolado internamente. Básicamente, necesitas resolver i. y ii. (ver las soluciones propuestas en los códigos y casillas vinculadas: despacho + defineProperty).
  2. Material-UI busca ayuda de la comunidad para proporcionar adaptadores para react-hook-form, cuando sea necesario (relacionado con # 15585).
  3. Cerramos este tema 👌

gracias, @oliviertassinari por la detallada respuesta. Investigaré más con las soluciones propuestas :)

Creo que la mayor parte del problema que mencionaste anteriormente con React es cuando cambias los componentes controlados, que es la parte en la que quiero mejorar.

Solo para aclarar:

  • Para reproducir el problema de cambio , vaya a https://codesandbox.io/s/heuristic-galileo-1wf8c y haga clic en el botón => registro faltante. Ahora, diríjase a https://codesandbox.io/s/silly-allen-72zz7 y vea cómo el enfoque de envío resuelve el problema.
  • Para reproducir el problema del cambio de valor , vaya a https://codesandbox.io/s/elastic-agnesi-osuuy y haga clic en el botón => registro faltante. Ahora, diríjase a https://codesandbox.io/s/sparkling-rain-3rebh y vea cómo el enfoque de Object.defiendProperty resuelve el problema.

Así que estoy bastante seguro de que puedes resolver eso en forma de gancho de reacción. Le agradeceríamos que pudiera probar / implementar estas correcciones y eliminar la culpa de nuestra parte de su documentación 😛.

Estos cambios realmente deberían ayudar con la tracción de su biblioteca de formularios, espero que lo apreciarán: D.

Creo que la mayor parte del problema que mencionó anteriormente con React es cuando cambia de componentes no controlados a controlados o controlados, que es la parte en la que quiero mejorar.

React advierte cuando el usuario cambia entre descontrolado y controlado. No entiendo tu punto.

Así que estoy bastante seguro de que puedes resolver eso en forma de gancho de reacción. Le agradeceríamos que pudiera probar / implementar estas correcciones y eliminar la culpa de nuestra parte de su documentación 😛.

DE NINGÚN MODO estoy culpando a MUI jaja, me encanta MUI (con mi pequeña estrella ⭐️). Como sabrá, react-hook-form es un chico nuevo en la ciudad, estaba tratando de llamar la atención o impulsar un tema en particular. Pido disculpas si encuentras así (culpa). nuevamente muchas gracias por su ayuda e investigación.

image
(Sin culpar)

Creo que la mayor parte del problema que mencionó anteriormente con React es cuando cambia de componentes no controlados a controlados o controlados, que es la parte en la que quiero mejorar.

React advierte cuando el usuario cambia entre descontrolado y controlado. No entiendo tu punto.

lo siento, quise decir componente controlado :) arregló mi comentario

@ bluebill1049 Impresionante :)

muchas gracias @oliviertassinari (eres muy amable)

Tenga en cuenta que Material-UI podría aplicar las mismas correcciones propuestas, pero no creo que debamos hacerlo, tendría dos inconvenientes: 1. Solo funcionaría con Material-UI, se tendría que hacer el mismo esfuerzo una y otra vez. 2. la propiedad de estos "hacks" debe permanecer en forma de gancho de reacción, ya que se origina a partir de la compensación que tomó la biblioteca (sin pasar por la API de React idiomática).

Hola chicos, en caso de que alguien intervenga en este problema. (Hemos estado trabajando en secreto en esto por un tiempo 😓)

Estamos trabajando en la próxima versión principal de RHF, que tiene algunas actualizaciones de calidad de vida, especialmente en torno al componente controlado. Tendremos un mejor soporte para la biblioteca de UI. El siguiente código resolverá setValue y defaultValue para la biblioteca de interfaz de usuario controlada mientras se mantiene la repetición mínima en el nivel de su aplicación / formulario, la repetición se aislará en el nivel de su componente de entrada.

La siguiente será la sintaxis cuando utilice V4 de RHF.

import TextField from '@material-ui/core/TextField';

const { control } = useForm();

<Controller as={TextField} control={control} name="firstName" rules={{ required: true }} />

Necesitas ayuda.
Tengo un problema con el campo de texto del material (probablemente también con otros mui).
Cuando el campo de texto está vacío, el primer almacén de claves es lento, lo mismo ocurre cuando cambia el valor a vacío.
Por alguna razón, vuelve a renderizar la forma completa.

Screen Shot 2020-02-11 at 3 21 25 AM

ezgif com-video-to-gif

NOTA RÁPIDA : Estoy escribiendo rápido, sin demora. retrasan parte se debe a la razón mencionada anteriormente.

Hola chicos, este problema persiste incluso si uso el controlador de react-hook-form :(
¿Se puede reabrir este problema? ¿O lo estoy haciendo mal?

Ejemplo: https://codesandbox.io/s/example-muitextfield-setvalue-with-react-hook-form-kqwq0?file=/index.js

Editar: una solución que estoy usando es InputLabelProps={isEdition && { shrink: isEdition }}
donde isEdition es una bandera que estoy usando en la pantalla de edición.

@Luccasoli por favor consulte el documento: https://react-hook-form.com/api#Controller

Hay un ejemplo con ejemplos de MUI: https://codesandbox.io/s/react-hook-form-controller-079xx

Lo siento @ bluebill1049 , pero no encontré ninguna situación similar en este ejemplo, y en la documentación no pude encontrar ningún accesorio que pudiera resolver este problema correctamente :(

Screen Shot 2020-04-15 at 9 21 56 am

@Luccasoli echa un vistazo a defaultValue

Lo intenté:

  • Intenté convertir los valores predeterminados dentro de useForm () en un valor de estado, y establecí ese estado dentro de useEffect ()
  • Intenté usar la misma idea, pero en defaultValue prop directamente cada controlador

En ambos sentidos, el campo de texto no reconoce que la entrada está llena y la etiqueta se mantiene sobre la entrada

Sí, pero es extraño mantener un valor predeterminado como ese, siempre trato de comenzar con un valor de cadena vacía para no mostrar un valor extraño al usuario.

Incluso podría mostrar un valor predeterminado "Cargando", pero el valor inicial vacío aún parece más interesante, ¿crees que es posible?

Editar: sí, también funciona con cadena vacía ... jajaja, gracias, juré que lo había intentado antes, pero parece que.

@ bluebill1049 Modifiqué tu demostración para mostrar el problema que estoy viendo y espero que tengas una buena solución.
https://codesandbox.io/s/react-hook-form-controller-n196b?file=/src/index.js
Intentar validar una casilla de verificación está marcado antes de habilitar un botón. Todos los demás campos que he usado funcionan como se esperaba, excepto la casilla de verificación.

Encontré esta caja de arena realmente muy útil para Material UI: hay ejemplos de controles deslizantes, Seleccionar y algunos otros.
https://codesandbox.io/s/react-hook-form-controller-079xx?file=/src/index.js

¿Fue útil esta página
0 / 5 - 0 calificaciones