Material-ui: Travailler avec react-hook-form

Créé le 8 nov. 2019  ·  40Commentaires  ·  Source: mui-org/material-ui

J'essaie de faire un formulaire simple avec react-hook-form et material-ui . J'aimerais pouvoir :

  1. soumettre / valider un formulaire
  2. réinitialiser le formulaire correctement
  3. charger correctement les données

Désolé, mauvaise recherche de problème, cela ressemble à un doublon de https://github.com/mui-org/material-ui/issues/17018.

  • [x] Le problème est présent dans la dernière version.
  • [x] J'ai recherché les problèmes de ce référentiel et je pense qu'il ne s'agit pas d'un doublon.

Comportement actuel 😯

La première étape fonctionne correctement.
La fonction de réinitialisation efface la valeur, mais l'état du TextField matériel-ui semble rester à "rempli", et les styles ne correspondent pas aux données effacées.
La fonction reset avec les valeurs initiales définit correctement la valeur, mais le comportement est le même qu'avec reset (enfin, l'inverse dans ce cas), les données sont chargées mais l'état interne du TextField n'est pas "rempli".

Comportement attendu 🤔

L'entrée material-ui doit actualiser son état interne lorsque les données sont chargées / effacées

Étapes pour reproduire 🕹

Vous pouvez essayer les trois boutons de ce CodePen :
https://codesandbox.io/s/material-demo-ywutu

  1. Soumettre : fonctionne correctement en validant les données.
  2. Réinitialise correctement mais l'état des TextFields n'est pas vide.
  3. Charge correctement les données mais l'état des TextFields n'est pas rempli.

J'ai déposé un problème sur le projet react-hook-form mais le propriétaire m'a dit d'en ouvrir un ici aussi, alors nous y sommes :)

enhancement external dependency

Commentaire le plus utile

J'ai ajouté la balise waiting for users upvotes . Je clos le sujet car nous ne sommes pas sûrs que les gens recherchent un tel soutien. Alors s'il vous plaît, votez pour ce problème si vous l'êtes. Nous prioriserons nos efforts en fonction du nombre de votes positifs.

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

Tous les 40 commentaires

J'ai ajouté la balise waiting for users upvotes . Je clos le sujet car nous ne sommes pas sûrs que les gens recherchent un tel soutien. Alors s'il vous plaît, votez pour ce problème si vous l'êtes. Nous prioriserons nos efforts en fonction du nombre de votes positifs.

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

bien nécessaire :pray::pray::pray: une solution de contournement ?

bien besoin !

Certainement nécessaire.

Une idée de ce que serait la solution ?

Je ne suis pas sûr de quelque chose de spécifique, mais je sais que j'ai commencé à utiliser les deux bibliothèques et j'aimerais vraiment voir des intégrations plus étroites entre les deux. React Hook Form et Material UI sont tout simplement parfaits ensemble. Leur prise en charge de TypeScript est également agréable.

Hé, @oliviertassinari merci d'y avoir jeté un coup d'œil. On dirait que MUI TextField fonctionne mieux avec l'API de l'entrée native maintenant ! C'est vraiment sympathique. Nous avions l'habitude d'avoir la superposition de texte d'espace réservé au-dessus du texte lorsque vous invoquez 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
Dans l'exemple ci-dessus, <Switch /> n'a pas été réinitialisé après l'appel de l'API reset .

Ce serait vraiment bien si nous pouvions avoir tous les composants liés au formulaire pour prendre en charge l'API d'entrée de formulaire native (définir et réinitialiser la valeur via la référence d'entrée). quelque chose à considérer (peut-être jusqu'à ce que la lib devienne plus populaire ❤️)

encore une fois, j'apprécie votre temps et vos efforts pour examiner ce problème (maintenir un ÉNORME projet open source comme MUI est fou pour moi et vous faites un travail incroyable pour la communauté React). En plus de cela, faites-moi savoir si je peux travailler de mon côté pour travailler aussi avec MUI.

À votre santé
Facture

@ bluebill1049 Merci de l'avoir regardé. La bibliothèque semble avoir une bonne traction, mais elle est encore loin derrière formik. Le commutateur réinitialisé est-il le seul problème que nous ayons ?

merci, @oliviertassinari pour la réouverture et l'examen de ce problème. 🙏 oui, vous avez raison react-hook-form est encore un nouveau garçon dans la ville et vous n'avez pas d'action si vous souhaitez attendre encore un peu pour voir si plus d'utilisateurs adoptent react-hook-form , ce qui Je pense que c'est tout à fait raisonnable (même si dans mon cœur, je veux désespérément que cela fonctionne avec MUI, hahaha a été égoïste😼). En attendant, je vais créer un tableau d'entrées compatible avec react-hook-form out

Si les choses fonctionnent bien avec react-hook-form et que l'utilisation augmente, nous pouvons peut-être envisager de travailler avec l'API d'entrée native (c'est ce que la forme de crochet de réaction utilise dans les coulisses), ce serait formidable d'obtenir input , select , radio et checkbox fonctionnent car ceux-ci sont l'utilisation principale du formulaire.

Pour info @oliviertassinari Je travaille sur quelque chose pour combler l'écart entre MUI et react-hook-form. https://github.com/react-hook-form/react-hook-form-input

Également confronté à un problème de réinitialisation et de chargement des données par défaut. Merci de vous pencher sur ce problème. Ou au moins fournir une solution de contournement pour le moment.

Hey @raikusy s'il vous plaît jeter un oeil au lien que j'ai posté ci-dessus, je pense que cela vous aidera. À long terme, il serait formidable que le composant MUI prenne en charge la forme native de l'API « reset » et la mise à jour de la valeur via le composant « ref », mais c'est un gros travail dont je suis sûr que MUI a beaucoup de fonctionnalités et d'idées alignées qui sont plus importants. Tout comme nous en avons discuté ci-dessus, jusqu'à ce que la forme de crochet de réaction devienne la bibliothèque grand public ou devienne populaire, MUI commencera à rechercher des solutions. J'espère que cela a du sens :) merci d'utiliser également le formulaire de crochet de réaction ❤️🤩🤟🏻

Pour info, ce composant wrapper permettra toujours à votre formulaire d'avoir 0 re-rendu. Parce que la mise à jour de l'état d'entrée est isolée dans le composant wrapper.🤩🤟🏻💃

Merci @bluebill1049 ça a l'air super. J'ai une condition où les champs de formulaire auront une valeur par défaut lorsque les données sont transmises à partir des accessoires. Le composant TextField fonctionnera-t-il également avec la solution ci-dessus ? De plus, je cherchais un meilleur exemple de transmission de valeurs par défaut avec des accessoires au formulaire. Les accessoires peuvent parfois provenir d'un appel api après que le formulaire a déjà été monté.

@raikusy, vous devriez pouvoir utiliser l'API reset/setValue avec le composant wrapper.
réinitialiser : pour tout le formulaire -> https://react-hook-form.com/api#setValue
setValue : pour les particuliers -> https://react-hook-form.com/api#reset

Je n'arrive pas à faire travailler <Slider /> avec RHF.

En l'utilisant comme :

      <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>

J'obtiens l'erreur suivante :

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 semble que le curseur ne prend pas en charge les accessoires de valeur :( Je vais faire une enquête à ce sujet. En attendant, vous devrez peut-être utiliser un registre personnalisé, qui est enregistré à useEffect

Merci beaucoup @bluebill1049

J'ai fini par faire quelque chose comme ça :

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;

Cela fonctionne comme prévu.

J'en avais bien besoin aussi

À long terme, il serait bon que le composant MUI prenne en charge la 'réinitialisation' de l'API native et la mise à jour de la valeur via le composant 'ref'.

@ bluebill1049 N'est-ce pas un problème avec React ou react-hook-form lui-même? Comment un développeur est-il censé « réagir » à un changement d'état d'entrée avec react-hook-form ?
Disons que je suis un développeur React qui crée une entrée personnalisée et que je souhaite styliser l'élément différemment lorsqu'il est rempli/vide, comment dois-je implémenter cela ? Il semble qu'aucun événement de changement ne soit jamais déclenché.

Avez-vous envisagé de déclencher un événement de modification lorsque votre bibliothèque modifie une valeur d'entrée "en dehors" du modèle déclaratif de React ? Comme c'est fait dans @test-library/react ?

Cela permettrait la prise en charge des composants Material-UI qui reposent sur des éléments d'entrée natifs, pour les autres, comme le Slider, un wrapper personnalisé serait toujours nécessaire. Le curseur a une valeur prop mais la signature de onChange est différente d'une entrée native. Je pense que ce serait génial de voir une bibliothèque d'intégration comme nous l'avons pour les autres bibliothèques de formulaires : #15585.


Je me demandais pourquoi ce problème avait reçu autant de votes positifs, je pense que je l'ai découvert 🙃 :

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

salut @oliviertassinari , merci de vous pencher à nouveau sur ce problème 👍

Disons que je suis un développeur React qui crée une entrée personnalisée et que je souhaite styliser l'élément différemment lorsqu'il est rempli/vide, comment dois-je implémenter cela ? Il semble qu'aucun événement de changement ne soit jamais déclenché.

Je chercherais un sélecteur CSS pour des solutions dans mon propre projet qui utilise des entrées natives, par exemple: sélectionnez un élément a une valeur vide et affichez un style. Une alternative, j'utiliserais l'API react-hook-form watch pour détecter la valeur vide et la transmettre comme prop (avec mon composant d'entrée encapsulé).

Avez-vous envisagé de déclencher un événement de modification lorsque votre bibliothèque modifie une valeur d'entrée "en dehors" du modèle déclaratif de React ? Comme c'est fait dans @test-library/react ?

Oui, nous le faisons à peu près sous react-hook-form-input . ??

Je crois aux composants non contrôlés pour la construction de formes après de nombreuses années de construction de formes contrôlées, cela facilite vraiment les choses. Cela ne résout peut-être pas tous les cas extrêmes (si vous travaillez sur Facebook LOL), mais cela facilite certainement ma vie professionnelle et celle des autres autour de moi lorsqu'il s'agit de créer des formulaires. Les entrées HTML sont elles-mêmes avec état et j'aimerais les intégrer dans cette bibliothèque (ne disant pas que c'est bien ou mal, mais une solution alternative).

J'aime tellement créer une application React, et c'est pourquoi créer de nombreux packages autour de celle-ci. Je comprends que React adopte des composants contrôlés. Cependant, react-hook-form n'empêche pas les développeurs de créer un formulaire contrôlé, car vous pouvez toujours personnaliser register à useEffect .

Conclusion:

Je pense que nous pouvons clore ce problème et je supprimerai le lien sur mon site Web lié à ce problème. En plus de cela, pourrais-je mettre à jour cette page pour inclure react-hook-form-input ?

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

Oui, nous le faisons à peu près sous react-hook-form-input.

@ bluebill1049 Cela ressemble à l'approche opposée à ma suggestion. Je comprends ce qui suit :

  • réagir-crochet-former :

    1. Il garde une trace des nœuds DOM d'entrée. Quand il doit changer la valeur, il fait input.value = 'x' . Ceci est problématique pour React, car il n'a aucun moyen de savoir que la valeur d'entrée a changé. Par exemple, aucun événement de modification n'est déclenché .

    2. Parce que react-hook-form doit écouter les changements de valeur d'entrée, il définit un écouteur d'événement "input" sur l'entrée . Ceci est problématique pour votre bibliothèque car les modifications apportées par React ne déclenchent aucun événement lorsque la valeur change à partir d'une entrée contrôlée .

  • react-hook-form-input : la bibliothèque contrôle l'entrée pour contourner les deux limitations précédentes de react-hook-form (i et ii).

Étant donné que 1. il est très peu probable que React joue bien pour prendre en charge l'approche de la forme de crochet de réaction et 2. que la forme de crochet de réaction ne fonctionne pas en dehors de la boîte avec des entrées contrôlées et pseudo-non contrôlées (celles qui modifient le valeur par défaut et celles qui n'écoutent qu'onChange), je proposerais que :

  1. react-hook-form corrige le problème contrôlé et pseudo-incontrôlé en interne. Fondamentalement, vous devez résoudre i. et ii. (voir les solutions proposées dans les codesandbox liés : dispatch + defineProperty).
  2. Material-UI demande l'aide de la communauté pour fournir des adaptateurs pour react-hook-form, en cas de besoin (lié à #15585).
  3. Nous fermons ce numéro

merci @oliviertassinari pour la réponse détaillée. Je vais faire une enquête plus approfondie avec vos solutions proposées :)

Je pense que la plupart des problèmes que vous avez mentionnés ci-dessus avec React surviennent lorsque vous changez de composants contrôlés, ce que je souhaite améliorer.

Juste pour être clair:

  • Pour reproduire le problème de changement , rendez-vous sur https://codesandbox.io/s/heuristic-galileo-1wf8c et cliquez sur le bouton => journal manquant. Maintenant, rendez-vous sur https://codesandbox.io/s/silly-allen-72zz7 et voyez comment l'approche de répartition résout le problème.
  • Pour reproduire le problème de changement de valeur , rendez-vous sur https://codesandbox.io/s/elastic-agnesi-osuuy et cliquez sur le bouton => journal manquant. Maintenant, rendez-vous sur https://codesandbox.io/s/sparkling-rain-3rebh et voyez comment l'approche Object.defiendProperty résout le problème.

Je suis donc à peu près sûr que vous pouvez résoudre ce problème sous forme de crochet de réaction. Nous vous serions reconnaissants si vous pouviez essayer/déployer ces correctifs et supprimer le blâme de notre côté de votre documentation 😛.

Ces changements devraient vraiment aider à la traction de votre bibliothèque de formulaires, j'espère que vous l'apprécierez :D.

Je pense que la plupart des problèmes que vous avez mentionnés ci-dessus avec React surviennent lorsque vous passez de composants non contrôlés à des composants contrôlés ou contrôlés, ce que je souhaite améliorer.

React avertit lorsque l'utilisateur bascule entre non contrôlé et contrôlé. Je ne comprends pas votre propos.

Je suis donc à peu près sûr que vous pouvez résoudre ce problème sous forme de crochet de réaction. Nous vous serions reconnaissants si vous pouviez essayer/déployer ces correctifs et supprimer le blâme de notre côté de votre documentation 😛.

EN AUCUN CAS je blâme MUI haha, j'adore MUI (avec ma petite étoile ⭐️). Comme vous le savez, react-hook-form est un nouveau venu dans la ville, j'essayais d'attirer l'attention ou l'élan sur la question en particulier. Je m'excuse si vous trouvez de cette façon (la faute). encore merci beaucoup pour votre aide et votre enquête.

image
(Pas de blâme)

Je pense que la plupart des problèmes que vous avez mentionnés ci-dessus avec React surviennent lorsque vous passez de composants non contrôlés à des composants contrôlés ou contrôlés, ce que je souhaite améliorer.

React avertit lorsque l'utilisateur bascule entre non contrôlé et contrôlé. Je ne comprends pas votre propos.

désolé je voulais dire composant contrôlé :) corrigé mon commentaire

@bluebill1049 Génial :)

merci beaucoup, @oliviertassinari (vous êtes très gentil)

Notez que Material-UI pourrait appliquer les mêmes correctifs proposés mais je ne pense pas que nous devrions le faire, cela aurait deux inconvénients: 1. cela ne fonctionnerait qu'avec Material-UI, le même effort devrait être fait encore et encore. 2. la propriété de ces "hacks" doit rester sous forme de crochet de réaction car elle provient du compromis pris par la bibliothèque (en contournant l'API React idiomatique).

Hé les gars, au cas où quelqu'un interviendrait dans ce problème. (Nous travaillons secrètement là-dessus depuis un moment 😓)

Nous travaillons sur la prochaine version majeure pour RHF, qui a quelques mises à jour de qualité de vie, notamment autour du composant contrôlé. Nous aurons un meilleur support pour la bibliothèque d'interface utilisateur. Le code suivant résoudra setValue et defaultValue pour la bibliothèque d'interface utilisateur contrôlée tout en maintenant un minimum de rendu au niveau de votre application/formulaire, le nouveau rendu sera isolé au niveau de votre composant d'entrée.

Ce qui suit sera la syntaxe lorsque vous utilisez la V4 de RHF.

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

const { control } = useForm();

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

Besoin d'aide.
J'ai un problème avec le champ de texte du matériel (probablement d'autres mui également).
Lorsque le champ de texte est vide, le premier magasin de clés est lent, il en va de même lorsque vous modifiez la valeur en vide.
Pour une raison quelconque, il restitue toute la forme.

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

ezgif com-video-to-gif

NOTE RAPIDE : Je tape vite, sans aucun délai. ils retardent une partie est due à la raison mentionnée ci-dessus.

Salut les gars, ce problème persiste même si j'utilise le contrôleur de react-hook-form :(
Ce problème peut-il être rouvert ? Ou est-ce que je le fais mal ?

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

Edit: Une solution que j'utilise est le InputLabelProps={isEdition && { shrink: isEdition }}
isEdition est un indicateur que j'utilise à l'écran d'édition.

@Luccasoli plz se référer à la doc : https://react-hook-form.com/api#Controller

Il y a un exemple avec des exemples MUI : https://codesandbox.io/s/react-hook-form-controller-079xx

Désolé @bluebill1049 , mais je

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

@Luccasoli regarde defaultValue

J'ai essayé:

  • J'ai essayé de transformer les defaultValues ​​à l'intérieur de useForm () une valeur d'état et de définir cet état à l'intérieur de useEffect ()
  • j'ai essayé d'utiliser la même idée, mais dans defaultValue prop directement chaque contrôleur

Dans les deux sens, le textField ne reconnaît pas que l'entrée est remplie et l'étiquette reste sur l'entrée

Oui, mais c'est étrange de garder une valeur par défaut comme ça, j'essaie toujours de commencer avec une valeur de chaîne vide pour ne pas montrer une valeur étrange à l'utilisateur.

Je pourrais même afficher une valeur par défaut "Loading", mais la valeur initiale vide semble toujours plus intéressante, pensez-vous que c'est possible ?

Edit : ouais, ça marche aussi avec une chaîne vide... hahaha, merci, j'aurais juré avoir essayé ça avant, mais il semble que.

@ bluebill1049 J'ai peaufiné votre démo pour montrer le problème que je vois et j'espère que vous avez une bonne solution.
https://codesandbox.io/s/react-hook-form-controller-n196b?file=/src/index.js
Essayer de valider une case à cocher est coché avant d'activer un bouton. Tous les autres champs que j'ai utilisés fonctionnent comme prévu, à l'exception de la case à cocher.

J'ai trouvé ce bac à sable vraiment très utile pour Material UI - Il existe des exemples pour les curseurs, Select et quelques autres.
https://codesandbox.io/s/react-hook-form-controller-079xx?file=/src/index.js

Cette page vous a été utile?
0 / 5 - 0 notes