React: L'événement de changement se déclenche plusieurs fois avant la fin de la composition IME

Créé le 21 mai 2015  ·  48Commentaires  ·  Source: facebook/react

Détails supplémentaires


Édition originale

Lorsque j'essayais cet exemple de https://facebook.github.io/react/blog/2013/11/05/thinking-in-react.html , tous les caractères chinois saisis par la méthode d'entrée du pinyin chinois déclencheraient trop de rendus comme :

screen shot 2015-05-21 at 14 04 36

En fait, je m'attendrais à ce que ceux-ci ne tirent pas avant de confirmer le caractère chinois.

Ensuite, j'ai essayé un autre type de méthode d'entrée - la méthode d'entrée wubi, j'ai obtenu ceci:

screen shot 2015-05-21 at 14 17 15

C'est bizarre aussi. J'ai donc fait un test dans jQuery :

screen shot 2015-05-21 at 14 05 12

Seulement après avoir appuyé sur la barre d'espace pour confirmer le caractère, l'événement keyup se déclencherait.

Je sais que cela peut être différent entre l'implémentation de jQuery keyup et react onChange , mais je m'attendrais à ce que jQuery keyup gère les caractères chinois au lieu de réagir onChange .

DOM Bug

Commentaire le plus utile

Bonjour, les gars de Facebook, en fait, ce problème pose un problème GRAVE : nous ne pouvons pas mettre à jour l'entrée de manière asynchrone avec l'entrée chinoise.
Par exemple, nous ne pouvons pas utiliser des sources de données réactives aux météores ou des magasins comme redux, car ils sont tous mis à jour de manière asynchrone.
Voici un exemple le plus simple pour montrer ce problème, il utilise setTimeout pour faire la mise à jour asynchrone:
https://jsfiddle.net/liyatang/bq6oss6z/1/

J'espère vraiment que vous pourrez résoudre ce problème rapidement, afin que nous ne gaspillions pas nos efforts pour le contourner ici et là et encore et encore.

Merci.

Voici ma solution de contournement . Si quelqu'un est confronté au même problème, vous pouvez jeter un œil

Tous les 48 commentaires

cc @salier :) - Que devons-nous faire ici?

Je pense que nous ne devrions pas tirer onChange tant que la chaîne IME n'est pas validée.

Une façon de gérer cela dans ChangeEventPlugin serait d'ignorer tous les événements input entre compositionstart et compositionend , puis d'utiliser l'événement input immédiatement suivant compositionend .

J'ai fait quelques tests rapides sur OSX Chrome et Firefox avec Simplified Pinyin et 2-Set Korean, et l'ordre des événements et les données semblent assez corrects. (Je prédis que nous aurons des problèmes avec IE Korean, mais nous aurons peut-être de la chance.)

Je pense que nous pouvons continuer à voir des problèmes avec des méthodes de saisie alternatives comme l'extension Google Input Tools, mais il peut y avoir des solutions de contournement pour cela.

Cela influence également la façon dont les caractères dialectiques sont tapés pour les langues latines. Même le fait d'appuyer longuement sur e puis d'utiliser la variante échoue ici.

Désolé, cela ne semble pas être lié. Mes excuses.

Y a-t-il une mise à jour? Souffrant de ce problème aussi.

Aucun actuellement - ce n'est pas une priorité pour nous en ce moment. Je serais heureux de consulter une demande de tirage si quelqu'un se penche sur la résolution de ce problème.

@salier Il semble que IE ne déclenche pas l'événement input après compositionend . J'ai testé sur IE11 et Edge sur Windows 10. Il se déclenche correctement dans Chrome et Firefox.

dans ie 9, l'événement Change se déclenche trop de fois lors de la nouvelle saisie de caractères chinois

Bonjour, les gars de Facebook, en fait, ce problème pose un problème GRAVE : nous ne pouvons pas mettre à jour l'entrée de manière asynchrone avec l'entrée chinoise.
Par exemple, nous ne pouvons pas utiliser des sources de données réactives aux météores ou des magasins comme redux, car ils sont tous mis à jour de manière asynchrone.
Voici un exemple le plus simple pour montrer ce problème, il utilise setTimeout pour faire la mise à jour asynchrone:
https://jsfiddle.net/liyatang/bq6oss6z/1/

J'espère vraiment que vous pourrez résoudre ce problème rapidement, afin que nous ne gaspillions pas nos efforts pour le contourner ici et là et encore et encore.

Merci.

Voici ma solution de contournement . Si quelqu'un est confronté au même problème, vous pouvez jeter un œil

J'ai fait un exemple simple pour montrer comment utiliser les événements compositionstart et compositionend pour éviter de saisir un IME chinois sur onchange problème d'événement
Voici le lien: https://jsfiddle.net/eyesofkids/dcxvas28/8/

@eyesofkids beau travail, cela pourrait être fait comme implémentation par défaut de onChange pour input, textarea ...

bon travail !

Je rencontrais le même problème et la solution de contournement de @eyesofkids fonctionne parfaitement (merci!).

Après avoir mis en place la solution de contournement, je plongeais dans le code source de React pour au moins essayer d'ajouter un test qui échouait pour cela - dans l'espoir d'ajouter plus tard le comportement attendu à la bibliothèque - bien que cela semble un peu compliqué pour quelqu'un qui ne connaît pas les éléments internes.

Au départ, je m'attendais à ce qu'un test similaire à ce qui est déjà disponible pour ChangeEventPlugin devrait fonctionner, c'est-à-dire simuler un compositionStart / compositionUpdate et vérifier l'absence de onChange callback était mis à la porte; vérifier également que onChange ne serait déclenché qu'une fois que compositionEnd été simulé. Cependant, cela ne semble pas fonctionner.

Par conséquent, je pensais que la vérification de ChangeEventPlugin.extractEvents() serait une approche réalisable, similaire à ce qui est fait dans les tests pour SelectEventPlugin . Ici, pour une raison quelconque, je reçois toujours undefined lors de l'extraction des événements.
Pour référence, voici le code de test que j'ai essayé dans _ChangeEventPlugin-test.js_:

  var EventConstants = require('EventConstants');
  var ReactDOMComponentTree = require('ReactDOMComponentTree');
  var topLevelTypes = EventConstants.topLevelTypes;

  function extract(node, topLevelEvent) {
    return ChangeEventPlugin.extractEvents(
      topLevelEvent,
      ReactDOMComponentTree.getInstanceFromNode(node),
      {target: node},
      node
    );
  }

  function cb(e) {
    expect(e.type).toBe('change');
  }
  var input = ReactTestUtils.renderIntoDocument(
    <input onChange={cb} value='foo' />
  );

  ReactTestUtils.SimulateNative.compositionStart(input);

  var change = extract(input, topLevelTypes.topChange);
  expect(change).toBe(null);

J'ai peur de ne pas savoir exactement comment on est censé déboguer ces tests, sinon j'aurais une image plus claire de ce qui se passe. Tout conseil sur la façon de procéder ou tout autre pointeur serait très apprécié.

La solution de contournement a soudainement éclaté dans Chrome 53+ et il semble qu'elle ne soit plus valide car ils ont changé l'ordre compositionend est déclenché : auparavant, cela se produisait avant textInput , maintenant après textInput . En conséquence, change ne sera pas déclenché s'il est interrompu en composition 😕.

https://github.com/suhaotian/react-input peut-être aider quelqu'un

Il existe une solution délicate pour Chrome v53. Pour appeler le handlechange après le déclenchement de compositionend .

handleComposition  = (event) => {

    if(event.type === 'compositionend'){
      onComposition = false

      //fire change method to update for Chrome v53
      this.handleChange(event)

    } else{
      onComposition = true
    }
  }

consultez la démo ici: https://jsfiddle.net/eyesofkids/dcxvas28/11/

@chenxsan avez-vous trouvé la solution?
vous pouvez détecter la compositionStart et laisser une variable égale à true.
Ensuite, pour utiliser la variable, que vous définissez, sur onChange pour voir si elle doit déclencher la requête

J'ai soumis un nouveau problème pour les composants contrôlés dans # 8683

La solution temporaire pour les composants incontrôlés et contrôlés (entrée, zone de texte) est téléchargée dans react-compositionevent .

Faisons en sorte que https://github.com/facebook/react/pull/8438 se produise.

@yesmeck très heureux de voir cette nouvelle.

J'ai vu le test se concentrer uniquement sur le Webkit, il devrait être séparé entre Chrome et Safari car Chrome modifie son ordre déclenché par l'événement compositionend après 53+.

@eyesofkids Ajout d'un nouveau

Juste pour ajouter de l'essence au feu, j'ai essayé de contourner ce problème et j'ai découvert que la version actuelle de safari iOS ne déclenche pas l'événement compositionend lors de l'utilisation de l'IME japonais Hiragana, je pense que c'est intentionnel car le menu de composition ne semble jamais fermé.
Sur @eyesofkids exemple la solution de contournement InputValue est jamais mis à jour, mais pour moi https://github.com/zhaoyao91/react-optimistic-input résout le problème avec le japonais IME.

Pour tous ceux qui recherchent une solution à cela, voici un composant prêt à l'emploi. https://github.com/aprilandjan/react-starter/blob/test/search-input/src/components/SearchInput.js Utilisez-le simplement à la place de l'élément d'entrée de texte normal et tout va bien.

@ zhaoyao91 votre solution de contournement fonctionne! Merci beaucoup.

hé les gars des nouvelles dans ce numéro?

Cela n'a pas été une priorité élevée car onChange déclenche trop souvent des problèmes. Où cela pose-t-il des problèmes dans votre application?

@sophiebits désolé a accidentellement cliqué sur le «X». Cela peut dégrader les performances si des opérations de filtrage ou des rappels de serveur sont utilisés dans les gestionnaires d'événements de modification. L'approche présentée dans https://github.com/facebook/react/issues/3926#issuecomment -316049951 est une bonne solution de contournement pour les entrées non contrôlées ou natives, mais ne correspond pas bien aux entrées contrôlées par React. On dirait que certains dans ce fil ont essayé de développer un PR, mais ont trouvé les internes un peu complexes - mais peut-être qu'un ingénieur de votre équipe pourrait le faire plus rapidement? https://github.com/facebook/react/issues/8683 est une bien meilleure description du vrai problème IMO.

Quelqu'un peut-il m'aider à comprendre: le problème est-il strictement lié aux appels supplémentaires onChange au milieu ? Ou obtenez-vous une valeur incorrecte à la fin?

Le test de la tentative de correction dans https://github.com/facebook/react/pull/8438 réussit si je supprime l'assertion sur le nombre d'appels de onChange . Je suppose donc que ce problème ne concerne que les appels supplémentaires onChange .

il n'y a pas d'appels onChange supplémentaires, il obtient juste la valeur incorrecte à la fin, cela ressemble plus à un problème onComposition.

@crochefluid Pouvez-vous créer un test d'échec pour cela? Similaire à ce que # 8438 a essayé de faire. Dans ce test, il n'y avait aucune valeur incorrecte.

@gaearon Je vais essayer. Avez-vous essayé ce test sur Safari (Mac / IOS)?

C'est un test Node mais il encode les séquences capturées à partir de différents navigateurs et appareils. Veuillez consulter sa source. Vous devrez ajouter des séquences qui échouent.

Je suppose donc que ce problème concerne uniquement les appels onChange supplémentaires.

Exactement.

Je reçois toujours ce problème. Il semble que ce problème soit ouvert depuis 3 ans, React prend-il en charge l'entrée chinoise dans les composants contrôlés pour le moment?

Voir aussi cela en japonais avec certains personnages ...

Voici un sandbox de code qui reproduit mon problème. On dirait que c'est lié aux formulaires. L'utilisation directe des entrées est très bien.

https://codesandbox.io/s/0m1760xqnl

J'ai ajouté quelques cas:
L'utilisation de l'état de réaction et des entrées simples est très bien
L'utilisation de l'état de réaction, des formulaires simples et des entrées simples est très bien
Nous utilisons un composant de formulaire basé sur le contexte qui ne fonctionne pas. Cela peut être un problème lié au contexte.

Problème résolu: je l'ai fait fonctionner dans codepen. Pour une raison quelconque, passer 'input' en tant que composant a fonctionné, lorsque vous passez (props) => pas.

Quelqu'un a-t-il une idée de la différence?

En fait, j'ai aussi essayé:

Travaux

<Field {...otherProps} component="input" />

Ne marche pas

<Field {...otherProps} component={(props) => <input {...props} />} />

Fonctionne assez bizarrement

const WrappedInput = (props) => <input {...props} />
...
<Field {...otherProps} component={WrappedInput} />

Il y a clairement de la magie ici que je ne comprends pas. 😕

Les mises à jour?

Cela semble provoquer un résultat incorrect lorsque IME est activé

e84721f3ec71a5ce043ef8290

J'ai rencontré le même problème que @otakustay
Il semble impossible de prendre en charge l'entrée contrôlée avec l'entrée IME. J'ai retracé la séquence des événements comme suit.

  1. L'utilisateur tape une lettre, par exemple w
  2. onChange est déclenché
  3. L'état est mis à jour avec une nouvelle valeur
  4. La nouvelle valeur est propagée jusqu'au input au moyen de l'attribut value .
  5. La "composition" de l'IME est interrompue à ce stade

    • Il y a une chaîne w dans l'élément d'entrée

    • Il existe également une chaîne w séparée stockée dans le tampon IME

  6. L'utilisateur tape une autre lettre, par exemple a
  7. La chaîne dans l'entrée a combine avec la chaîne le tampon IME pour produire wwa .
  8. Répétez les étapes 1 à 7 pour obtenir un groupe de caractères en double.

J'ai remarqué que le bogue ne se produit que si l'entrée est restituée> 15 ms après l'événement compositionUpdate après la prochaine peinture.

Pour le moment, ma seule solution est de m'éloigner des entrées contrôlées.

Edit : Voici une simple reproduction: https://jsfiddle.net/kbhg3xna/
Edit2 : Voici ma solution de contournement hacky: https://jsfiddle.net/m792qtys/ cc: @otakustay

Des mises à jour à ce sujet?

mettre à jour ??

Une mise à jour pour ceci?

Abasourdi, j'ai été confronté à cette question

Intéressant, semble que le problème ne concerne pas seulement le onChange à plusieurs reprises. Si nous ne définissons pasState entre onCompositionStart et onCompositionEnd , la réaction "contrôlera" la valeur telle quelle. Cette action interrompra la composition. Cela signifie que nous n'obtiendrons pas l'événement onCompositionEnd ...... (Si je me trompe, mentionnez-moi plz.) Mais nous ne pouvons que changer l'état immédiatement (sinon nous devrons faire face au problème @ knubie mentionne). Une reproduction ici (ressemble à un composant "à moitié contrôlé"): https://gist.github.com/cpdyj/6567437d96c315e9162778c8efdfb6e8

Mais je suis tellement surpris que le problème n'ait pas de solution pendant cinq ans 😢

@hellendag Je pense que nous ne devrions pas tirer onChange tant que la chaîne IME n'est pas

Je ne pense pas que ce soit une solution valide car un composant pourrait vouloir connaître la chaîne IME "non validée" pour par exemple les options de filtrage dans une liste en tant que types d'utilisateurs.

Je ne suis pas sûr si l'approche que j'utilise dans cet autre fil pourrait aider ceux qui rencontrent ce problème, mais voici un lien au cas où: https://github.com/facebook/react/issues/13104#issuecomment -691393940

les mises à jour?

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

Questions connexes

trusktr picture trusktr  ·  3Commentaires

hnordt picture hnordt  ·  3Commentaires

jimfb picture jimfb  ·  3Commentaires

zpao picture zpao  ·  3Commentaires

varghesep picture varghesep  ·  3Commentaires