React: Fornece uma maneira de lidar com valores de formulário preenchidos automaticamente pelo navegador em componentes controlados

Criado em 22 fev. 2014  ·  80Comentários  ·  Fonte: facebook/react

Quando há um componente controlado para nomes de formulários que o usuário salvou em seu navegador (comum com campos de nome de usuário / senha), o navegador às vezes renderiza a página com valores nesses campos sem disparar eventos onChange. Se o usuário enviar o formulário, o estado do componente não refletirá o que está sendo mostrado ao usuário.

Ao fazer experiências com isso, parece que os dados estão lá no carregamento (testado registrando this.refs.myinput.getDOMNode (). Value)

DOM Bug

Comentários muito úteis

Você tentou definir o atributo 'nome' para a entrada? funciona para mim. o onChange é acionado no preenchimento automático do usuário

Todos 80 comentários

Isso parece discutir um pouco mais: http://stackoverflow.com/a/11710295

me cc

(Dica @visionscaper : pressione "Inscrever-se" na coluna da direita.)

Alguma atualização ou sugestão de práticas recomendadas sobre este? O evento de preenchimento automático polyfill parece uma solução de marreta.

O Safari (8) despacha eventos de alteração no preenchimento automático, mas eles não borbulham, portanto não alcançam o manipulador de reação.

Foi encerrada uma discussão relacionada em https://github.com/angular/angular.js/issues/1460 , com algumas sugestões, uma delas utilizando https://github.com/tbosch/autofill-event para disparar alterar evento no preenchimento automático, manualmente.

Acho que podemos fechar aqui também.

Seria bom ter o evento autofill como parte do React, possível como um addon. Essa funcionalidade será necessária para praticamente todos os usuários do React para validação de formulários. O script autofill-event também adiciona uma dependência para jQuery, o que pode ser indesejável em muitos casos.

Este é um bug do navegador que afeta todos os navegadores de maneira um pouco diferente. Eu acho que só porque angular apontou para tentar contornar ou consertar isso não significa reagir deveria. É uma coisa comum, mas eu entendo se isso é um "wontfix".

Não sou muito versado nos vários rastreadores de bug do navegador, mas seria bom se alguém que pudesse encontrar ou abrir problemas para isso. Acho que a equipe de reação tem mais peso do que a maioria dos usuários ao abrir um problema sobre isso. E poderíamos distribuir os tíquetes aqui para os desenvolvedores de reação que estão interessados.

Alcancei o fio angular. O Firefox tem problemas com campos de senha (https://bugzilla.mozilla.org/show_bug.cgi?id=950510 ainda está aberto), nenhuma palavra sobre o bug do safari #, o cromo foi corrigido.

Os problemas já estão sendo rastreados em alguns lugares - https://github.com/angular/angular.js/issues/1460#issuecomment -53947546

O problema do Chrome foi encerrado, mas claramente não funciona no Chrome 50 com React 0.14.8.

nenhuma correção ainda?

Eu sinto que isso estava funcionando por um tempo e quebrou de novo recentemente?

alguma atualização sobre este problema?

Aqui está um trecho da minha solução para este problema:

export default class Input extends Component {
  static propTypes = {
    value: PropTypes.string,
    onFieldChange: PropTypes.func,
  };

  static defaultProps = {
    value: '',
  }

  componentDidMount() {
    this._listener = setInterval(() => {
      if (!this.input || this._previousValue === this.input.value) {
        return;
      }

      this._previousValue = this.input.value;

      const evt = document.createEvent('HTMLEvents');
      evt.initEvent('input', true, true);
      this.input.dispatchEvent(evt);
    }, 20);
  }

  componentWillUnmount() {
    clearInterval(this._listener);
  }

  refInput = (input) => this.input = input;

  render() {
    const { label,
      value,
      onFieldChange,
    } = this.props;

    this.input = this.input || { value };

    return (
        <input
            value={this.input.value}
            onChange={onFieldChange}
            ref={this.refInput}
        />
    );
  }
}

NOTA: value vem do estado e onFieldChange atualiza o estado com o novo valor

O código setInterval é do https://github.com/Pephers/react-autofill

Alguém pode confirmar se esse problema foi corrigido no iOS 10.2? Não consigo reproduzir agora ...

Ainda estou tendo problemas no iOS 10.2 com a versão do Chrome 55.0.2883.79 ... Ao contrário do que foi descrito acima, para mim, o conteúdo preenchido automaticamente pisca brevemente no formulário e é removido novamente.
Portanto, agora está consistente com o que está armazenado no estado, no entanto, o preenchimento automático ainda não funciona ...

Estou reproduzindo o mesmo problema encontrado por @irisSchaffer. Eu tenho um aplicativo isomórfico, onde renderizo uma página estática com react e express, então no cliente exporto os adereços e uso o mesmo componente de página.

Mesmo quando não está manipulando o valor de entrada da senha por meio do react, o componente react do cliente exclui a senha salva da entrada, mesmo quando o cromo a mostra brevemente. Quando desativo o javascript do navegador, a senha salva permanece em seu lugar.

Este problema é visível apenas no Chrome, usando sua última versão, 58.

Não relacionado a react, a senha salva não é acessível através de element.value até que haja um evento disparado no dom, como foco, qualquer evento chave, etc. propriedade.

+1. qualquer correção ou hacks?

Ainda estou enfrentando esse problema no iOS 10.3.3 Chrome 60.0.3112.89.

O preenchimento automático funciona, preenche o campo, mas não altera o estado.

Solução alternativa para decorador: https://github.com/Pephers/react-autofill

Solução de componente genérico:

/**
  Trigger onChange event after browser auto-fill.

  <strong i="8">@see</strong> https://github.com/facebook/react/issues/1159
  <strong i="9">@example</strong> <AutoFillWatch component={ref =>
    <input required type="password" ref={ref} />
  }/>
*/
class AutoFillWatch extends Component {
  static propTypes = {
    // Auto-fill component like: <input type="password"
    component: PropTypes.func.isRequired,

    // component pass-through reference
    ref: PropTypes.func,
  }

  componentDidMount() {
    this._listener = setInterval(() => {
      if (!this.input || this._previousValue === this.input.value) {
        return;
      }

      this._previousValue = this.input.value;

      const evt = document.createEvent('HTMLEvents');
      evt.initEvent('input', true, true);
      this.input.dispatchEvent(evt);
    }, 100);
  }

  componentWillUnmount() {
    clearInterval(this._listener);
  }

  componentDidMount() {
    const {ref} = this.props
    if(ref) {
      console.log('ref', this.input);
      ref(this.input)
    }
  }

  refInput = (input) => this.input = input;

  render() {
    const {component} = this.props
    return component(this.refInput)
  }
}

O Chrome para iOS (certifique-se de testar com o preenchimento automático do Chrome, e não com as sugestões do teclado do iOS) apenas emite change ao preencher os valores automaticamente. O Mobile Safari, por outro lado, emite focus , keydown , input , keyup , change e blur , como faz Chrome e Safari no Mac.

O React não usa o evento change para <input /> normais, o que parece ser a causa raiz deste problema: https://github.com/facebook/react/blob/e932ad68bed656eed5295b61ba74e5d0857902ed/src/renderers /dom/shared/eventPlugins/ChangeEventPlugin.js#L66 -L71

Não seria possível fazer o React onChange também ser acionado em eventos DOM change ? Haveria algum mal nisso?

Problema relacionado para Chrome iOS: https://bugs.chromium.org/p/chromium/issues/detail?id=705275

Testei o preenchimento automático e os eventos com a seguinte página:

<html>

<head>
  <script type="text/javascript">
    window.onload = function () {
      let elements = document.querySelectorAll('input');
      let actions = document.getElementById('actions')
      let events = 'focus blur keydown keyup change input'.split(' ');

      elements.forEach(element => {
        events.forEach(event => {
          element.addEventListener(event, e => {
            console.log(e);
            let eTypeNode = document.createTextNode(element.name + ' > ' + e.type + ":" + e.code + ":" + e.keyIdentifier);
            actions.appendChild(eTypeNode);
            actions.appendChild(document.createElement('br'));
          })
        })
      })
    };
  </script>
</head>

<body>
  <form>
    <input type="text" name="name" id="a" autocomplete="name" />
    <input type="email" name="email" id="b" autocomplete="email" />
    <input type="tel" name="tel" id="c" autocomplete="tel" />
  </form>
  <div id="actions"></div>
</body>

</html>

O evento Change é emitido no Chrome v62 quando você envolve as entradas por um elemento <form /> .

há um manipulador de eventos onInput que obterá o valor de um campo de entrada se ele for alterado.

Ainda vejo algum comportamento incomum aqui com o preenchimento automático no iOS. O decorador de preenchimento automático acima parece funcionar bem com o preenchimento automático simples, mas não com os atalhos de preenchimento automático fornecidos pelo teclado.

Isso deve ser corrigido no Chrome para iOS agora: https://chromium.googlesource.com/chromium/src/+/55518e17850cac0bdc6fca7b24092bea479e34db. Não tenho certeza de quando este patch será incluído em uma versão lançada.

Por que onChange deve ser usado?
Por que TEMOS que usar 'onChange' mas não o 'evento de mudança'

class Input extends Component {
    componentDidMount(){
        this.input.addEventListener('change', (e)=>{
            this.props.onChange(this.props.field, e.target.value)
        })
    }
    render(){
        const { className, name, label, autofill, field, onBlur, onChange, value, error, visited, required, type, maxLength } = this.props
        return (
            <div className={ [styles.inputWrap, className || ''].join(' ') } onBlur={e => onBlur(field)}>
                <input ref={n => this.input = n} id={field} name={name || field} type={ type || 'text' } defaultValue={ value }
                 autoComplete={ autofill } maxLength={maxLength} />
                <div className={ [styles.placeholder, value? styles.active:''].join(' ') }>
                    <FormattedMessage id={label} />
                    <i className={styles.required}>{required? '*':''}</i>
                    <span className={ styles.error }>{ visited? error:'' }</span>
                </div>
            </div>
        )
    }
}

O evento Change é emitido no Chrome v62 quando você envolve as entradas por um elemento <form /> .

Confirmo que esta solução funciona para o Chrome para preenchimento automático de números de telefone via autoComplete="tel"
https://github.com/catamphetamine/react-phone-number-input/issues/101

As soluções acima usando this._previousValue !== this.input.value infelizmente, só funcionam para iOS Safari. O .value iOS Chrome ainda está vazio após um preenchimento automático.

Não tenho ideia de como as pessoas têm lidado com o preenchimento automático de formulários ao usar componentes controlados. Considere este cenário de login:

  • e-mail de preenchimento automático: nada muda, mesmo com o hack dispatchEvent, o Chrome relatará o e-mail .value como vazio
  • Comece a escrever o valor no campo de senha: o e-mail é perdido porque o estado React pensa que está vazio

A menos que haja uma maneira de fazer o Chrome relatar o valor, não consigo pensar em uma solução diferente de usar componentes não controlados, validação de entrada html5 e obter valores de formulário no envio como antigamente.

Você pode rastrear (e marcar com estrela) o problema aqui: https://bugs.chromium.org/p/chromium/issues/detail?id=813175

Não consegui fazer com que a solução acima funcionasse em @DominicTobias. Existem várias camadas de problemas. A primeira era que this.input.value sempre voltava em branco. No entanto, descobri que se você usar document.getElementById em cada loop, então document.getElementById(id).value - você receberá um valor de volta.

Isso não resolve o problema de dispatchEvent , mas pelo menos você pode obter o valor preenchido automaticamente e fazer coisas com ele (por exemplo, apenas chamar o manipulador onChange uma entrada controlada).

@wlingke bom saber (e que estranho)! Vou ter que seguir esse caminho também, se eles não corrigirem o bug a tempo para o meu lançamento

@wlingke Ao configurar uma demonstração para os caras do Chrome, percebi uma coisa - este não é um problema com o Chrome, eu deveria ter lido os comentários acima com mais cuidado (em particular o comentário @oscar-b). onChange é um evento sintético no React que não usa o evento change , o que me parece muito estranho.

Você pode até ver na demonstração abaixo que ele se comporta de maneira diferente, mais como se estivesse ouvindo um evento input . Quando você usa o evento change real, ele funciona corretamente no iOS Chrome.

Então, eu sugeriria obter uma referência para o elemento e apenas ouvir o evento de mudança real, bem como o evento onChange que parece ser o evento input se você precisar atualizar o estado como o o usuário está digitando.

demonstração: https://kind-stallman-f3c045.netlify.com/

@DominicTobias Eu tentei anteriormente os eventos change e input separadamente, bem como os dois ao mesmo tempo naquele decorador, mas não consegui fazê-los funcionar em meu aplicativo.

Também não tenho certeza se isso muda as coisas ... mas há uma diferença entre o preenchimento automático de UM campo e o preenchimento automático de VÁRIOS campos. O evento input funcionou bem ao preencher automaticamente um campo. No entanto, no mobile chrome, você pode preencher automaticamente um conjunto de campos de uma vez com o teclado (como nome, sobrenome, e-mail, tudo com um toque).

Nesse segundo cenário, o decorador permite que o primeiro campo seja preenchido automaticamente de maneira adequada (o primeiro campo significa o campo que está atualmente em foco). No entanto, o decorador (que é anexado a todos os 3 campos) não parece funcionar nos outros campos.

@wlingke Interessante, adicionei mais alguns campos, mas ao preencher automaticamente todos os três de uma vez no iOS Chrome estou recebendo corretamente os eventos de alteração nativamente (mas 0 para a versão React abaixo):

screen shot 2018-03-08 at 19 29 15

(A captura de tela é do navegador para desktop, mas estou obtendo o mesmo resultado no meu telefone)

@DominicTobias Acho que se você usar o evento input - que é o que usei anteriormente, funcionará totalmente no Desktop. E trabalhe pela primeira entrada em Mobile.

input evento onChange . O evento change só é arquivado após um elemento perder o foco pelo que entendi (https://stackoverflow.com/questions/17047497/what-is-the-difference-between-change-and-input-event- para um elemento de entrada)

Sim, a reação por algum motivo vinculou onChange ao evento input : https://stackoverflow.com/questions/38256332/in-react-whats-the-difference-between-onchange-and-oninput

Então, para manter as coisas simples, eu também o chamo em meu componente Input para eventos de mudança reais (bem como os de entrada normais). Agora está funcionando no iOS Chrome. Experimente e me diga!

componentDidMount() {
  this.inputRef.addEventListener('change', this.onChange);
}

onChange = (event) => {
  // React actually uses the input even for onChange, this causes autofill to
  // break in iOS Chrome as it only fires a change event.
  if (this.props.onChange) {
    this.props.onChange(event);
  }
}

componentWillUnount() {
  this.inputRef.removeEventListener('change', this.onChange);
}

Editar: o Chrome deve ter sido corrigido na v65, mas as pessoas estão relatando que ainda não funciona: /

Obrigado pela explicação Dominic. Corrigimos esse comportamento em dezembro. Agora disparamos eventos keydown, change, input e keyup.
https://chromium-review.googlesource.com/c/chromium/src/+/771674

Também tínhamos uma correção para React.
https://chromium-review.googlesource.com/c/chromium/src/+/844324

embora isso corrija o comportamento do preenchimento automático, ainda não invoca o manipulador onChange.

Eu também levantei um problema sobre isso e o desenvolvedor tinha certeza de que seria corrigido em 65 ... https://bugs.chromium.org/p/chromium/issues/detail?id=813175

Também estou ouvindo o evento nativo change como @DominicTobias e funciona para mim no iOS Chrome. Estou ativando onChange do redux-form no listener de evento nativo anexado na montagem.

Também estou usando o seletor input:-webkit-autofill para estilizar.

Veja o resultado por si mesmo na parte inferior do https://labrewlangerie.com (formulário de contato).

Parece que essa correção está finalmente chegando ao Chrome iOS! Não tenho certeza em qual versão, pois parece ter sido mesclada em 1º de dezembro.

https://bugs.chromium.org/p/chromium/issues/detail?id=705275#c11
https://chromium-review.googlesource.com/c/chromium/src/+/771674

O mesmo aqui no Chrome 65, React 15.6.

É uma pena, Mahmadi disse que estava acontecendo em 13 de março na v65 :(

Comentário 15 por [email protected] , 9 de março
A correção não está no Chrome 64. Meu mal. O Chrome 65 terá (a ser lançado a partir de 13 de março). Acabei de testar seu site de demonstração de eventos nativos e ele funciona no Chrome 65. Agradeço o acompanhamento disso.

https://bugs.chromium.org/p/chromium/issues/detail?id=813175

Tente acessar aqui em seu telefone e verificar: https://kind-stallman-f3c045.netlify.com/native.html

O que é realmente estranho é que na v65 ele está funcionando nativamente, mas embora esteja recebendo uma entrada, mesmo não sendo recebido no React! Precisa de mais investigação. Não tenho certeza de como reage ao anexar o manipulador (ou se ele está fazendo isso no elemento do documento como um manipulador de clique, por exemplo).

Nativamente, posso ver o evento de entrada acontecendo agora (https://kind-stallman-f3c045.netlify.com/native.html):

native

Mas de alguma forma o React não está recebendo nenhum desses eventos (https://kind-stallman-f3c045.netlify.com):

react

add onBlur = {this.handleChange} na entrada

Equipe KlarnaUI tem um truque interessante para lidar com esta questão explorando o onAnimationStart evento e :-webkit-autofill classe pseudo conforme descrito neste artigo - https://medium.com/@brunn/detecting -autofilled- fields-in-javascript-aed598d25da7

Usamos esse hack em nossos aplicativos, ele funciona bem (só poderia ser testado no Chrome). Vou tentar criar um shim usando essa técnica para que seja genérico.

Alguma atualização sobre o problema?

up, qual é o melhor truque para o momento?

@ericflo @sophiebits

Este problema ainda parece persistir, alguma atualização?

@Pixelatex @Aarbel veja minha resposta um pouco mais adiante - https://github.com/facebook/react/issues/1159#issuecomment -371604044

Basicamente, o React ouve o evento input e não o change one para o onChange, de forma que a resposta apenas escuta os dois.

@DominicTobias Tentei fazer isso, mas precisamos ter um clique real em algum lugar da página para fazer isso funcionar. o evento não registra até então.

Tenho lutado com o problema há cerca de um dia no total. Posso definitivamente listar o que NÃO funciona no Desktop Chrome 67 e no React 15.6.0:

  1. onAnimationStart com input:-webkit-autofill https://medium.com/@brunn/detecting -autofilled-fields-in-javascript-aed598d25da7 - dispara prematuramente (o formulário ainda não foi preenchido)
  2. this.inputRef.addEventListener("transitionend", this.doSomething, false) em combinação com input:-webkit-autofill css transição - dispara na hora certa, mas você não pode ativar a página, como @Pixelatex mencionou
  3. this.inputRef.addEventListener("change", this.doSomething) - nem mesmo dispara até você clicar na página
  4. onBlur={this.doSomething} - não dispara um evento

Novamente, essas soluções NÃO FUNCIONAM, infelizmente. O HTML não contém o valor preenchido automaticamente, a menos que você cutuque a página. O mais próximo é 2, pois você pode digitar document no console e ele irá despertar a página, e até agora programaticamente isso não funcionou.
@DominicTobias A sua solução funciona no Chrome para desktop?

Na verdade, eu tenho um hack sujo. Se você usar a solução 2 do comentário anterior, pode confiar em [aqui vem a sujeira] "Dados de formulário salvos são dados válidos". Então você pode pegar a transição após o preenchimento automático do evento concluído e habilitar um botão Enviar, digamos. Veja como:

css:

input:-webkit-autofill {
    transition: background-color 0.1s ease-in-out 0s;
}

no construtor:

this.autofillCompleted = this.autofillCompleted.bind(this)

Dentro de sua classe React Component:

componentDidMount(){
if(this.myInputRef)
      this.myInputRef.addEventListener("transitionend", this.autofillCompleted, false)
}
autofillCompleted(){
    this.setState({ submitActive: true });
}
componentWillUnmount(){
    if(this.myInputRef)
      this.myInputRef.removeEventListener("transitionend", this.autofillCompleted, false)
}

Dentro do JSX:

<FormControl
            inputRef={(node) => this.myInputRef= node}
/>

PS para componentes básicos (como input ), use ref prop em vez de inputRef

No desktop Chrome mais recente e no Safari do iOS 12, agrupar elementos em <form> faz com que o preenchimento automático emita um evento onChange.

@rxb embrulhado em <p> </p> ?

@basarat desculpe, esqueci minha marcação de código e a tag desapareceu ... <form> tag

Alguma atualização sobre este problema?

Alguma atualização sobre este problema?

Se houvesse atualizações, eles estariam neste assunto.

Não poste se você não tiver nada significativo a acrescentar - você está enviando spam para todos que estão inscritos neste problema. Obrigado.

Eu também levantei um problema sobre isso e o desenvolvedor tinha certeza de que seria corrigido em 65 ... https://bugs.chromium.org/p/chromium/issues/detail?id=813175

Essa correção, infelizmente, não foi coordenada com a equipe React. Não estávamos cientes de que o Chrome no iOS agora define uma propriedade que aconteceu acidentalmente para acionar o manipulador de alterações em versões anteriores. Não foi intencional da nossa parte apoiar isso - e já fizemos uma alteração que removeu o comportamento (não sabíamos que o Chrome começou a confiar nele).

Se você estiver trabalhando em um navegador e adicionando um hack específico do React, certifique-se de inserir alguém da equipe do React.

Alguém pode resumir isso ao bug atual . React trata AMBOS os eventos change e input para entradas. Se o preenchimento automático disparar qualquer um deles, ele deve funcionar. Portanto, não está claro se a questão original aqui ainda é relevante. OU há algumas coisas aqui que podem ser problemas diferentes

  • Os valores são preenchidos automaticamente antes da "renderização", por exemplo, havia uma página SSR que reage é hidratante. Acredito que usamos o valor correto nesse caso (cc @nhunzaker)
  • As entradas não disparam eventos no preenchimento automático
  • entradas disparam eventos diferentes do que o React está escutando (isso deve ser resolvido a partir da v15)

Há algo que perdi aqui e alguém sabe quais navegadores se comportam ou não corretamente?

A propósito, queremos considerar isso como parte de # 9657 - idealmente, tudo o que fizermos deve ser parcialmente a serviço de ajudar a resolver este problema.

@jquense usamos o valor correto, mas não enviamos um evento de mudança:

http://react-hydration.surge.sh/hydration

  1. Desmarque "Auto-hidratar"
  2. Mude o valor
  3. Clique em Hidratar
  4. Sem alteração :(

ok, eu também pesquisei:

Acho que há dois problemas aqui:

  • Valores que são preenchidos pelo navegador antes que os hidratos do React sejam perdidos.
  • O Chrome no IOS não dispara nenhum evento no preenchimento automático

aqui está um site que você pode usar para testar: https://jquense.github.io/browser-test-pages/autofill/login/

Pelo que posso dizer, todas as outras plataformas e navegadores funcionam bem para selecionar valores preenchidos automaticamente

observe que o acima é uma página de gatsby, então _também_ demonstra o problema de SSR

@nhunzaker, você tem ideias inteligentes sobre o case Chrome do IOS? parece que Vue punted https://github.com/vuejs/vue/issues/7058 também

React não renderiza o preenchimento automático desativado

Registrei um novo bug do Chrome para o problema do Chrome no iOS: https://bugs.chromium.org/p/chromium/issues/detail?id=895898

Você tentou definir o atributo 'nome' para a entrada? funciona para mim. o onChange é acionado no preenchimento automático do usuário

@eatsjobs Usamos o nome de attr, mas temos o mesmo problema.

eu testei

$$(':-webkit-autofill')

Funciona no Chrome 70, retorna as entradas preenchidas automaticamente.

@QuantumInformation o mesmo para mim :(

handleOnChange = e => {
  this.setState({ email: e.target.value }, () => {
    alert(this.state.email)
  })
}
<form>
  <input
    name="email"
    type="email"
    placeholder="Enter Your Email"
    autocomplete="email"
    value={this.state.email}
    onChange={e => this.handleOnChange(e)}
   />
</form>

Eu tento assim, parece que tudo funciona bem.
O preenchimento automático definiu meu estado corretamente. (ios 12)

Para quem se deparou com esse problema recentemente, ele é causado intencionalmente pelos navegadores para evitar riscos de segurança.

Se pudermos acessar os valores preenchidos automaticamente assim que a página for carregada, seria muito fácil escrever código malicioso para extrair informações em um formulário destinado a phishing. Não dando ao usuário nenhuma chance de reagir. Provavelmente parte do motivo pelo qual autocomplete="off" é ignorado pelos navegadores.

Para superar esse problema, precisamos:

  1. Aceite o fato de que não teremos (e nunca teremos) acesso aos valores preenchidos automaticamente quando o nó DOM for montado
  2. Abrace as questões de segurança levantadas pelos navegadores

Para resolver esse problema, pense em como os formulários foram originalmente projetados e destinados a serem usados. Quando o usuário clica em <button type="submit" /> dentro de <form> ele está basicamente dizendo "ei, esta ação foi planejada pelo usuário, agora vamos avaliar os valores do formulário".

Considere este exemplo de um SignInForm realmente simples escrito em React:

import React from 'react';

class SignInForm extends React.Component {
  constructor() {
    this.state = {
      email: '',
      password: '',
    };

    this.handleEmail = this.handleEmail.bind(this);
    this.handlePassword = this.handlePassword.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleEmail(event) {
    this.setState({ email: event.target.value });
  }

  handlePassword(event) {
    this.setState({ password: event.target.value });
  }

  handleSubmit() {
   console.log(this.state.email); // The email value
   console.log(this.state.password); // The password value
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
         <input
            name="email"
            type="text"
            value={this.state.email}
            onChange={this.handleEmail}
            placeholder="Email"
          />
         <input
            name="password"
            type="text"
            value={this.state.password}
            onChange={this.handlePassword}
            placeholder="Password"
          />
          <button type="submit" onClick={this.handleSubmit}>Sign In</button>
        </form>
    );
  }
}

export default SignInForm;

Após o envio, o formulário irá atualizar e avaliar os campos de entrada de acordo.

Isso significa:

  1. Não podemos desativar o botão de envio de forma alguma
  2. Toda a validação deve ocorrer assim que o usuário clicar neste botão

Em minha opinião, esta é a abordagem mais pragmática e vai poupar muita dor de cabeça. Espero que isso ajude outras pessoas no futuro.

Edit: Para aqueles que não estão familiarizados com React, você pode dar uma olhada neste link para uma implementação básica de um formulário e algumas informações adicionais interessantes: https://html.spec.whatwg.org/multipage/forms.html

Para quem se deparou com esse problema recentemente, ele é causado intencionalmente pelos navegadores para evitar riscos de segurança.

Se pudermos acessar os valores preenchidos automaticamente assim que a página for carregada, seria muito fácil escrever código malicioso para extrair informações em um formulário destinado a phishing. Não dando ao usuário nenhuma chance de reagir. Provavelmente parte do motivo pelo qual autocomplete="off" é ignorado pelos navegadores.

Para superar esse problema, precisamos:

  1. Aceite o fato de que não teremos (e nunca teremos) acesso aos valores preenchidos automaticamente quando o nó DOM for montado
  2. Abrace as questões de segurança levantadas pelos navegadores

Para resolver esse problema, pense em como os formulários foram originalmente projetados e destinados a serem usados. Quando o usuário clica em <button type="submit" /> dentro de <form> ele está basicamente dizendo "ei, esta ação foi planejada pelo usuário, agora vamos avaliar os valores do formulário".

Considere este exemplo de um SignInForm realmente simples escrito em React:

import React from 'react';

class SignInForm extends React.Component {
  constructor() {
    this.state = {
      email: '',
      password: '',
    };

    this.handleEmail = this.handleEmail.bind(this);
    this.handlePassword = this.handlePassword.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleEmail(event) {
    this.setState({ email: event.target.value });
  }

  handlePassword(event) {
    this.setState({ password: event.target.value });
  }

  handleSubmit() {
   console.log(this.state.email); // The email value
   console.log(this.state.password); // The password value
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
         <input
            name="email"
            type="text"
            value={this.state.email}
            onChange={this.handleEmail}
            placeholder="Email"
          />
         <input
            name="password"
            type="text"
            value={this.state.password}
            onChange={this.handlePassword}
            placeholder="Password"
          />
          <button type="submit" onClick={this.handleSubmit}>Sign In</button>
        </form>
    );
  }
}

export default SignInForm;

Após o envio, o formulário irá atualizar e avaliar os campos de entrada de acordo.

Isso significa:

  1. Não podemos desativar o botão de envio de forma alguma
  2. Toda a validação deve ocorrer assim que o usuário clicar neste botão

Em minha opinião, esta é a abordagem mais pragmática e vai poupar muita dor de cabeça. Espero que isso ajude outras pessoas no futuro.

Edit: Para aqueles que não estão familiarizados com React, você pode dar uma olhada neste link para uma implementação básica de um formulário e algumas informações adicionais interessantes: https://html.spec.whatwg.org/multipage/forms.html

Obrigado pelo resumo, no entanto, estou completamente confuso. Você diz que quando enviarmos um formulário, ele será "atualizado de acordo". Isso significa que ele disparará eventos de alteração adicionais para cada campo preenchido automaticamente antes de disparar o evento de envio? Ou significa que, quando o evento submit é disparado, os valores agora podem ser lidos por meio de refs? Se for o primeiro, podemos construir componentes como você mostrou no snippet. Se for o último, então precisaremos adotar uma abordagem baseada em referência para formulários no futuro.

@thomasjulianstoelen O que você quis dizer?

@dwoodwardgb
Na minha experiência (com o Chrome, pelo menos), ele tem atualizado os campos na primeira interação do usuário com a página (cliques, envios de formulários, etc), e tem enviado eventos com a mudança, permitindo que as variáveis ​​do modelo sejam atualizadas. Ainda não testei outros navegadores.

Você pode definir o atributo

Investigou esse problema um pouco mais: o Chromium fez uma alteração para emitir eventos nativos de "mudança" e "entrada" com base neste relatório de bug: https://bugs.chromium.org/p/chromium/issues/detail?id= 813175. No entanto, por algum motivo, o React ainda não aciona o evento onChange em resposta a nenhum desses eventos nativos. Isso provavelmente está relacionado à lógica de desduplicação do React (https://github.com/facebook/react/issues/10135) ou ao fato de que os eventos emitidos programaticamente pelo Chrome no iOS carregam a bandeira isTrusted=false .

Alguém da equipe React pode dar uma olhada mais profunda no manipulador de eventos React onChange para descobrir por que o evento não está sendo acionado? @gaearon ou @zpao (suposições aleatórias)?

Nesse ínterim, estou usando o evento onInput , que escuta o evento nativo "input" diretamente.

Acho que este é o commit no Chrome que quebrou o comportamento:

https://chromium.googlesource.com/chromium/src/+/49bf3cbf7cc6d70643197a604090f8729f9d7404%5E%21/components/autofill/ios/fill/resources/fill.js

Ele remove o sinalizador simulated do evento de alteração, o que provavelmente faz com que a lógica de desduplicação ignore esses eventos.

@nfiacco esse commit é de 2018, esta edição foi aberta em 2014, então na superfície isso não

Eu voltei de 2022

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