Material-ui: Trabalhando com a forma react-hook

Criado em 8 nov. 2019  ·  40Comentários  ·  Fonte: mui-org/material-ui

Estou tentando fazer um formulário simples com react-hook-form e material-ui . Eu gostaria de ser capaz de:

  1. enviar / validar um formulário
  2. redefina o formulário corretamente
  3. carregar dados corretamente

Desculpe, pesquisa de problema incorreta, parece uma duplicata de https://github.com/mui-org/material-ui/issues/17018.

  • [x] O problema está presente na versão mais recente.
  • [x] Pesquisei os problemas deste repositório e acredito que não seja uma duplicata.

Comportamento Atual 😯

A primeira etapa funciona corretamente.
A função de redefinição limpa o valor, mas o estado do material-ui TextField parece permanecer em "preenchido" e os estilos não correspondem aos dados limpos.
A função de reset com valores iniciais configurou corretamente o valor, mas o comportamento é o mesmo que com reset (bem, o oposto neste caso), os dados são carregados mas o estado interno do TextField não é "preenchido".

Comportamento esperado 🤔

A entrada material-ui deve atualizar seu estado interno quando os dados são carregados / limpos

Passos para reproduzir 🕹

Você pode tentar os três botões neste CodePen:
https://codesandbox.io/s/material-demo-ywutu

  1. Enviar: funciona corretamente validando os dados.
  2. Redefine corretamente, mas o estado dos TextFields não está vazio.
  3. Carrega dados corretamente, mas o estado dos TextFields não é preenchido.

Registrei um problema no projeto react-hook-form, mas o proprietário me disse para abrir um aqui também, então aqui estamos :)

enhancement external dependency

Comentários muito úteis

Eu adicionei a tag waiting for users upvotes . Estou encerrando a questão, pois não temos certeza se as pessoas estão procurando por esse suporte. Então, por favor, vote a favor deste problema se você for. Priorizaremos nosso esforço com base no número de votos positivos.

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

Todos 40 comentários

Eu adicionei a tag waiting for users upvotes . Estou encerrando a questão, pois não temos certeza se as pessoas estão procurando por esse suporte. Então, por favor, vote a favor deste problema se você for. Priorizaremos nosso esforço com base no número de votos positivos.

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

muito necessário: pray :: pray :: pray: alguma alternativa?

muito necessário!

Definitivamente necessário.

Alguma ideia de qual seria a solução?

Não tenho certeza sobre algo específico, mas sei que comecei a usar as duas bibliotecas e realmente gostaria de ver integrações mais estreitas entre as duas. React Hook Form e Material UI são ótimos juntos. Seu suporte para TypeScript também é bom.

Ei, @oliviertassinari , obrigado por dar uma olhada nisso. Parece que MUI TextField está funcionando melhor com a API de entrada nativa agora! Isso é muito bom. Costumávamos ter o texto do marcador de posição sobreposto ao texto quando você invocava 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
No exemplo acima, <Switch /> não redefiniu após reset API invocada.

Seria muito bom se pudéssemos ter todos os componentes relacionados ao formulário para suportar a API de entrada de formulário nativo (definir e redefinir o valor por meio da referência de entrada) Eu entendo que é um grande trabalho e suportar uma pequena lib como o react-hook-form é algo a ser considerado (talvez até se a biblioteca ficar mais popular ❤️)

Mais uma vez, agradeço seu tempo e esforço para analisar este problema (manter um ENORME projeto de código aberto como o MUI é uma loucura para mim e você está fazendo um trabalho incrível para a comunidade React). Além disso, deixe-me saber se eu posso trabalhar em alguma coisa para trabalhar com o MUI também.

Saúde
Conta

@ bluebill1049 Obrigado por olhar para ele. A biblioteca parece ter uma boa tração, mas ainda está muito atrás de formik. A redefinição do switch é o único problema que temos?

obrigado, @oliviertassinari por reabrir e examinar este problema. 🙏 sim, você está certo react-hook-form ainda é um garoto novo na cidade e você não tem como agir se quiser esperar mais um tempo para ver se mais usuários estão adotando react-hook-form , o que Eu acho que é totalmente razoável (mesmo que dentro do meu coração eu esteja desesperado para querer que funcione com a MUI, hahaha fui egoísta😼). Enquanto isso, criarei uma tabela de entradas compatível com react-hook-form out the box (talvez até com uma codesandbox também) e a postarei aqui também.

Se as coisas funcionarem bem com o formulário react-hook e o uso crescendo, talvez possamos considerar trabalhar com a API de entrada nativa (que é o que o react-hook-form usa nos bastidores), seria ótimo obter input , select , radio e checkbox funcionando, pois são o uso principal do formulário.

Também está enfrentando problemas com a redefinição e o carregamento de dados padrão. Por favor, analise este problema. Ou pelo menos forneça uma solução por enquanto.

Ei @raikusy , dê uma olhada no link que postei acima, acho que vai te ajudar. A longo prazo, seria ótimo para o componente MUI suportar api de forma nativa 'redefinir' e atualizar o valor por meio do componente 'ref', mas esse é um preço alto de trabalho que tenho certeza que o MUI tem muitos recursos e ideias alinhados que são mais importantes. Assim como discutimos acima, até que a forma de gancho de reação se torne a biblioteca principal ou se torne popular, o MUI começará a investigar as soluções. Espero que façam sentido :) obrigado por usar a forma de gancho de reação também ❤️🤩🤟🏻

Para sua informação, esse componente de invólucro ainda permitirá que seu formulário seja 0 re-renderizado. Porque a atualização do estado de entrada é isolada dentro do componente wrapper.🤩🤟🏻💃

Obrigado @ bluebill1049, isso parece ótimo. Eu tenho uma condição em que os campos do formulário terão um valor padrão quando os dados forem passados ​​dos props. Então, o componente TextField funcionará com a solução acima também? Também estava procurando por qualquer exemplo melhor de passar valores padrão com adereços para o formulário. Em algum momento, os adereços podem vir de uma chamada de API depois que o formulário já foi montado.

@raikusy você deve ser capaz de usar a API reset / setValue com o componente wrapper.
redefinir: para todo o formulário -> https://react-hook-form.com/api#setValue
setValue: for individual -> https://react-hook-form.com/api#reset

Não consigo fazer <Slider /> trabalhar com RHF.

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

Estou tendo o erro a seguir:

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 o controle deslizante não oferece suporte a props de valor :( Vou fazer algumas investigações sobre isso. Enquanto isso, você pode ter que usar o registro personalizado, que é o registro em useEffect

Muito obrigado @ bluebill1049

Acabei fazendo algo assim:

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 conforme o esperado.

Muito precisava disso também

No longo prazo, seria ótimo para o componente MUI oferecer suporte a 'redefinição' da API de formato nativo e atualizar o valor por meio do componente 'ref'.

@ bluebill1049 Não é um problema com o React ou com o próprio
Digamos que eu seja um desenvolvedor React construindo uma entrada personalizada e quero estilizar o elemento de maneira diferente quando estiver preenchido / vazio. Como devo implementar isso? Parece que nenhum evento de mudança é disparado.

Você já pensou em disparar um evento de alteração quando sua biblioteca altera um valor de entrada "fora" do modelo declarativo do React? Como é feito em @ test-library / react?

Isso habilitaria o suporte de componentes Material-UI que dependem de elementos de entrada nativos, para os outros, como o Slider, um wrapper personalizado ainda seria necessário. O controle deslizante tem um valor prop, mas a assinatura de onChange é diferente de uma entrada nativa. Acho que seria ótimo ver uma biblioteca de integração como temos para as outras bibliotecas de formulários: # 15585.


Eu estava me perguntando por que esse problema recebeu tantos votos positivos, acho que descobri 🙃:

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

ei @oliviertassinari , obrigado por olhar mais de perto para este problema novamente 👍

Digamos que eu seja um desenvolvedor React construindo uma entrada personalizada e quero estilizar o elemento de maneira diferente quando estiver preenchido / vazio. Como devo implementar isso? Parece que nenhum evento de mudança é disparado.

Eu procuraria o seletor CSS para soluções em meu próprio projeto que está usando entradas nativas, por exemplo: selecionar um elemento tem um valor vazio e exibir um estilo. Uma alternativa, eu usaria o react-hook-form watch API para detectar o valor vazio e passar para baixo como prop (com meu componente de entrada empacotado).

Você já pensou em disparar um evento de alteração quando sua biblioteca altera um valor de entrada "fora" do modelo declarativo do React? Como é feito em @ test-library / react?

Sim, estamos praticamente fazendo isso em react-hook-form-input . 😄

Eu acredito em componentes não controlados para a construção de formas, depois de muitos anos de construção controlada de forma, isso realmente torna as coisas muito mais fáceis. Pode não resolver todos os casos extremos (se você trabalhar no Facebook LOL), mas certamente torna minha vida profissional e de outras pessoas mais fácil quando se trata de construir formulários. As entradas HTML têm estado próprias e eu adoraria abraçá-las nesta biblioteca (não dizendo que é certo ou errado, mas uma solução alternativa).

Eu adoro construir o aplicativo React, e é por isso que construir tantos pacotes em torno dele. Eu entendo que o React inclui componentes controlados. No entanto, react-hook-form não está impedindo os desenvolvedores de construir o formulário controlado, porque você ainda pode fazer register customizado em useEffect .

Conclusão:

Acho que podemos encerrar esse problema e removerei o link do meu site relacionado a ele. Além disso, eu poderia atualizar esta página para incluir react-hook-form-input ?

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

Sim, estamos basicamente fazendo isso sob a entrada react-hook-form-input.

@ bluebill1049 Parece a abordagem oposta à minha sugestão. Eu entendo o seguinte:

  • forma de gancho reativo:

    1. Ele mantém o controle dos nós DOM de entrada. Quando precisa alterar o valor, ele faz input.value = 'x' . Isso é problemático para o React, pois ele não tem como saber se o valor de entrada foi alterado. Por exemplo, nenhum evento de mudança é acionado .

    2. Como o react-hook-form precisa ouvir as mudanças de valor de entrada, ele define um ouvinte de evento de "entrada" na entrada . Isso é problemático para sua biblioteca, pois as alterações feitas pelo React não acionam nenhum evento quando o valor muda de uma entrada controlada .

  • react-hook-form-input: a biblioteca controla a entrada para contornar as duas limitações anteriores do react-hook-form (ie ii).

Dado que 1. é muito improvável que o React funcione bem para suportar a abordagem da forma reativa e 2. essa forma reativa não funciona fora da caixa com entradas controladas e pseudo-descontroladas (aquelas que alteram o valor padrão e aqueles que só ouvem onChange), eu proporia que:

  1. react-hook-form corrige o problema controlado e pseudo não controlado internamente. Basicamente, você precisa resolver i. e ii. (veja as soluções propostas nos códigos e caixas vinculados: dispatch + defineProperty).
  2. O Material-UI busca assistência da comunidade para fornecer adaptadores para a forma reativa, quando necessário (relacionado ao # 15585).
  3. Encerramos este problema 👌

obrigado, @oliviertassinari pela resposta detalhada. Farei uma investigação mais aprofundada com suas soluções propostas :)

Acredito que a maior parte do problema que você mencionou acima com o React é quando você alterna os componentes controlados, que é a parte que desejo melhorar.

Só para ficar claro:

  • Para reproduzir o problema de mudança , vá para https://codesandbox.io/s/heuristic-galileo-1wf8c e clique no botão => log ausente. Agora, vá para https://codesandbox.io/s/silly-allen-72zz7 e veja como a abordagem de despacho resolve o problema.
  • Para reproduzir o problema de mudança de valor , acesse https://codesandbox.io/s/elastic-agnesi-osuuy e clique no botão => log ausente. Agora, vá para https://codesandbox.io/s/sparkling-rain-3rebh e veja como a abordagem Object.defiendProperty resolve o problema.

Portanto, tenho certeza de que você pode resolver isso na forma de gancho de reação. Agradeceríamos se você pudesse tentar / implantar essas correções e remover a culpa de nossa parte de sua documentação 😛.

Essas alterações devem realmente ajudar com a tração de sua biblioteca de formulários, espero que você goste: D.

Acredito que a maior parte do problema que você mencionou acima com o React é quando você muda de componentes não controlados para controlados ou controlados, que é a parte que desejo melhorar.

React avisa quando o usuário alterna entre não controlado e controlado. Eu não entendo seu ponto.

Portanto, tenho certeza de que você pode resolver isso na forma de gancho de reação. Agradeceríamos se você pudesse tentar / implantar essas correções e remover a culpa de nossa parte de sua documentação 😛.

De jeito nenhum, estou culpando a MUI haha, eu amo a MUI (com minha estrelinha ⭐️). Como você deve saber, a forma reativa-gancho é um garoto novo na cidade, eu estava tentando obter alguma atenção ou impulso sobre esse assunto em particular. Peço desculpas se você encontrar esse caminho (culpa). mais uma vez, muito obrigado por sua ajuda e investigação.

image
(Não Culpando)

Acredito que a maior parte do problema que você mencionou acima com o React é quando você muda de componentes não controlados para controlados ou controlados, que é a parte que desejo melhorar.

React avisa quando o usuário alterna entre não controlado e controlado. Eu não entendo seu ponto.

desculpe, eu quis dizer componente controlado :) corrigiu meu comentário

@ bluebill1049 Incrível :)

muito obrigado, @oliviertassinari (você é muito gentil)

Observe que o Material-UI poderia aplicar as mesmas correções propostas, mas não acho que devíamos, teria duas desvantagens: 1. só funcionaria com o Material-UI, o mesmo esforço precisaria ser feito continuamente. 2. a propriedade desses "hacks" deve permanecer na forma de gancho de reação, pois se origina da troca que a biblioteca obteve (contornando a API React idiomática).

Ei pessoal, caso alguém entre nesse problema. (Estamos trabalhando nisso secretamente há algum tempo 😓)

Estamos trabalhando na próxima versão principal do RHF, que tem algumas atualizações de qualidade de vida, especialmente em torno do componente controlado. Teremos um suporte melhor para a biblioteca de UI. O código a seguir resolverá setValue e defaultValue para a biblioteca de IU controlada, enquanto ainda mantém o mínimo de renderização em seu nível de aplicativo / formulário, a nova renderização será isolada em seu nível de componente de entrada.

O seguinte será a sintaxe quando você estiver usando V4 de RHF.

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

const { control } = useForm();

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

Preciso de ajuda.
Estou tendo um problema com o campo de texto do material (provavelmente outro mui também).
Quando o campo de texto está vazio, o primeiro armazenamento de chaves é lento, o mesmo acontece quando você altera o valor para vazio.
Por alguma razão, ele renderiza novamente todo o formulário.

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

ezgif com-video-to-gif

NOTA RÁPIDA : Estou digitando rápido, sem demora. eles atrasam parte é devido ao motivo mencionado acima.

Oi pessoal, este problema persiste mesmo se eu usar o controlador de react-hook-form :(
Este problema pode ser reaberto? Ou estou fazendo errado?

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

Edit: Uma solução que estou usando é InputLabelProps={isEdition && { shrink: isEdition }}
onde isEdition é um sinalizador que estou usando na tela de edição.

@Luccasoli plz consulte o documento: https://react-hook-form.com/api#Controller

Há um exemplo com exemplos de MUI: https://codesandbox.io/s/react-hook-form-controller-079xx

Desculpe @ bluebill1049 , mas não encontrei nenhuma situação semelhante neste exemplo e na documentação não consegui encontrar nenhum adereço que pudesse resolver este problema adequadamente :(

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

@Luccasoli, dê uma olhada em defaultValue

Eu tentei:

  • Tentei transformar defaultValues ​​em useForm () em um valor de estado e definir esse estado em useEffect ()
  • tentei usar a mesma ideia, mas em defaultValue prop diretamente cada controlador

De ambas as maneiras, o textField não reconhece que a entrada está preenchida e o rótulo mantém a entrada

Sim, mas é estranho manter um defaultValue como esse, eu sempre tento começar com um valor de string vazio para não mostrar um valor estranho para o usuário.

Eu poderia até exibir um valor padrão "Carregando", mas o valor inicial vazio ainda parece mais interessante, você acha que é possível?

Edit: sim, funciona com string vazia também ... hahaha, obrigado, eu jurei que já tinha tentado isso antes, mas parece que sim.

@ bluebill1049 Ajustei sua demonstração para mostrar o problema que estou vendo e espero que você tenha uma boa solução.
https://codesandbox.io/s/react-hook-form-controller-n196b?file=/src/index.js
A tentativa de validar uma caixa de seleção é marcada antes de habilitar um botão. Todos os outros campos que usei funcionam conforme o esperado, exceto a caixa de seleção.

Achei esta caixa de areia realmente útil para a IU de materiais - há exemplos de controles deslizantes, Select e alguns outros.
https://codesandbox.io/s/react-hook-form-controller-079xx?file=/src/index.js

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

activatedgeek picture activatedgeek  ·  3Comentários

zabojad picture zabojad  ·  3Comentários

sys13 picture sys13  ·  3Comentários

FranBran picture FranBran  ·  3Comentários

ghost picture ghost  ·  3Comentários