React: El evento de cambio activa más veces antes de que finalice la composición de IME

Creado en 21 may. 2015  ·  48Comentarios  ·  Fuente: facebook/react

Detalles extra


Emisión original

Cuando estaba probando este ejemplo de https://facebook.github.io/react/blog/2013/11/05/thinking-in-react.html , cualquier carácter chino ingresado por el método de entrada pinyin chino dispararía demasiadas representaciones como :

screen shot 2015-05-21 at 14 04 36

En realidad, esperaría que no disparen antes de confirmar el carácter chino.

Luego probé otro tipo de método de entrada: método de entrada wubi, obtuve esto:

screen shot 2015-05-21 at 14 17 15

También es extraño. Entonces hice una prueba en jQuery :

screen shot 2015-05-21 at 14 05 12

Solo después de presionar la barra espaciadora para confirmar el carácter, se activará el evento keyup .

Sé que podría ser diferente entre la implementación de jQuery keyup y reaccionar onChange , pero esperaría la forma en que jQuery keyup maneja los caracteres chinos en lugar de reaccionar onChange .

DOM Bug

Comentario más útil

Hola, chicos de Facebook, de hecho, este problema causa un problema SERIO : no podemos actualizar la entrada de forma asincrónica con la entrada china.
Por ejemplo, no podemos usar fuentes de datos reactivas a meteoritos o tiendas como redux, porque todos los comentarios se actualizan de forma asincrónica.
Aquí hay un ejemplo más simple para mostrar este problema, usa setTimeout para hacer una actualización asíncrona:
https://jsfiddle.net/liyatang/bq6oss6z/1/

Realmente espero que pueda solucionar esto rápidamente, para que no desperdiciemos esfuerzos para solucionarlo aquí y allá y una y otra vez.

Gracias.

Aquí está mi solución . Si alguien se enfrenta al mismo problema, puede echar un vistazo

Todos 48 comentarios

cc @salier :) - ¿Qué debemos hacer aquí?

Creo que no deberíamos disparar onChange hasta que la cadena IME esté confirmada.

Una forma de manejar esto en ChangeEventPlugin sería ignorar todos los eventos input entre compositionstart y compositionend , luego usar el evento input inmediatamente siguiendo compositionend .

Hice algunas pruebas rápidas en OSX Chrome y Firefox con Simplified Pinyin y 2-Set Korean, y el orden y los datos de los eventos parecen lo suficientemente correctos. (Predigo que tendremos problemas con IE Korean, pero es posible que tengamos suerte).

Creo que podemos seguir viendo problemas con métodos de entrada alternativos como la extensión Google Input Tools, pero puede haber soluciones para eso.

Esto también influye en cómo se escriben los caracteres dialécticos para los idiomas latinos. Incluso la pulsación larga e y luego usar la variante están fallando aquí.

Lo siento, esto parece no estar relacionado. Mis disculpas.

¿Hay alguna actualización? Sufriendo de este problema también.

Ninguno actualmente, esto no es una prioridad para nosotros en este momento. Estaría feliz de ver una solicitud de extracción si alguien se sumerge en solucionar esto.

@salier Parece que IE no dispara el evento input después de compositionend . He probado en IE11 y Edge en Windows 10. Se dispara correctamente en Chrome y Firefox.

en ie 9, el evento Change se dispara demasiadas veces al ingresar caracteres chinos nuevamente

Hola, chicos de Facebook, de hecho, este problema causa un problema SERIO : no podemos actualizar la entrada de forma asincrónica con la entrada china.
Por ejemplo, no podemos usar fuentes de datos reactivas a meteoritos o tiendas como redux, porque todos los comentarios se actualizan de forma asincrónica.
Aquí hay un ejemplo más simple para mostrar este problema, usa setTimeout para hacer una actualización asíncrona:
https://jsfiddle.net/liyatang/bq6oss6z/1/

Realmente espero que pueda solucionar esto rápidamente, para que no desperdiciemos esfuerzos para solucionarlo aquí y allá y una y otra vez.

Gracias.

Aquí está mi solución . Si alguien se enfrenta al mismo problema, puede echar un vistazo

Hice un ejemplo simple para hacer una demostración de cómo usar los eventos compositionstart y compositionend para evitar ingresar IME chino en el problema del evento onchange .
Aquí está el enlace: https://jsfiddle.net/eyesofkids/dcxvas28/8/

@eyesofkids buen trabajo, esto podría hacerse como la implementación predeterminada de onChange para input, textarea ...

Buen trabajo !

Estaba teniendo el mismo problema y la solución de

Después de tener la solución en su lugar, me sumergí en el código fuente de React para al menos intentar agregar una prueba fallida para esto, con la esperanza de agregar más tarde el comportamiento esperado a la biblioteca, aunque parece un poco complicado para alguien que no está familiarizado con los componentes internos.

Inicialmente esperaba que una prueba similar a la que ya está disponible para ChangeEventPlugin debería funcionar, es decir, simulando un compositionStart / compositionUpdate nativo y verificando que no se haya devuelto la llamada onChange despedido; además, la comprobación de onChange solo se dispararía una vez que se simulara compositionEnd . Sin embargo, esto no parece funcionar.

Por lo tanto, estaba pensando que tal vez verificar ChangeEventPlugin.extractEvents() sería un enfoque factible, similar a lo que se hizo en las pruebas para SelectEventPlugin . Aquí, por alguna razón, siempre obtengo undefined cuando extraigo los eventos.
Como referencia, este es el código de prueba que probé dentro de _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);

Me temo que no sé exactamente cómo se supone que uno debe depurar estas pruebas; de lo contrario, tendría una idea más clara de lo que está sucediendo. Cualquier orientación sobre cómo proceder o cualquier otra sugerencia será muy apreciada.

La solución se rompió repentinamente en Chrome 53+ y parece que ya no es válida porque cambiaron el orden compositionend se disparó : anteriormente sucedía antes de textInput , ahora después de textInput . Como consecuencia de esto, change no se disparará si se cancela mientras está en composición 😕.

https://github.com/suhaotian/react-input tal vez ayudar a alguien

Existe una solución complicada para Chrome v53. Para llamar al handlechange después de que se dispare compositionend .

handleComposition  = (event) => {

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

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

    } else{
      onComposition = true
    }
  }

consulte la demostración aquí: https://jsfiddle.net/eyesofkids/dcxvas28/11/

@chenxsan ¿encontraste la solución?
puede detectar la composición Comienzo y dejar una variable igual a verdadera.
Luego, use la variable, que estableció, en onChange para ver si debería disparar la consulta

Envié un nuevo problema para componentes controlados en # 8683

La solución temporal para componentes controlados y no controlados (entrada, área de texto) se carga en react-composicionevent .

@yesmeck muy feliz de ver esta noticia.

Vi que la prueba solo se enfocaba en el Webkit, debería estar separado en Chrome y Safari porque Chrome cambia su orden activada por evento compositionend después de 53+.

@eyesofkids Se agregó un nuevo caso de prueba para Chrome menores de 53 años.

Solo para agregar más leña al fuego, he estado tratando de solucionar este problema y descubrí que la versión actual de iOS safari no activa el evento compositionend cuando se usa el IME japonés de Hiragana, creo que esto es intencional ya que el menú de composición nunca parece estar cerrado.
En la solución alternativa de ejemplo de @eyesofkids, inputValue nunca se actualiza, aunque para mí https://github.com/zhaoyao91/react-optimistic-input soluciona el problema con el IME japonés.

Para cualquiera que busque una solución para esto, aquí tiene un componente listo para usar. https://github.com/aprilandjan/react-starter/blob/test/search-input/src/components/SearchInput.js Simplemente úselo en lugar del elemento de entrada de texto normal y todo está bien.

@ zhaoyao91 ¡ tu solución simplemente funciona! muchas gracias.

hola chicos alguna noticia en este numero?

No ha sido una alta prioridad porque onChange disparar con demasiada frecuencia rara vez causa problemas. ¿Dónde está causando problemas en su aplicación?

@sophiebits lo siento, accidentalmente hizo clic en la 'X'. Esto puede degradar el rendimiento si se utilizan operaciones de filtrado o devoluciones de llamada del servidor en los controladores de eventos de cambio. El enfoque que se muestra en https://github.com/facebook/react/issues/3926#issuecomment -316049951 es una buena solución para las entradas nativas o no controladas, pero no se correlaciona bien con las entradas controladas por React. Parece que algunos en este hilo han intentado desarrollar un PR, pero encontraron los aspectos internos un poco complejos, pero ¿tal vez un ingeniero de su equipo podría hacerlo más rápido? https://github.com/facebook/react/issues/8683 es una descripción mucho mejor del problema real, en mi opinión.

¿Alguien puede ayudarme a entender: el problema está estrictamente en llamadas onChange adicionales en el medio ? ¿O obtiene un valor incorrecto al final?

La prueba del intento de corrección en https://github.com/facebook/react/pull/8438 pasa si elimino la afirmación sobre la cantidad de veces que se llama onChange . Así que supongo que este problema solo se trata de las llamadas adicionales onChange .

no hay llamadas onChange adicionales, solo está obteniendo el valor incorrecto al final, parece más un problema de onComposition.

@crochefluid ¿Puede crear una prueba fallida para esto? Similar a lo que intentó hacer # 8438. En esa prueba, no hubo ningún valor incorrecto.

@gaearon , lo intentaré. ¿Probaste esa prueba en safari (mac / IOS)?

Es una prueba de nodo, pero codifica secuencias capturadas desde diferentes navegadores y dispositivos. Consulte su fuente. Debería agregar secuencias que fallan.

Así que supongo que este problema solo se trata de las llamadas onChange adicionales.

Exactamente.

Sigo teniendo este problema. Parece que este problema ha estado abierto durante 3 años, ¿React admite la entrada china en componentes controlados en este momento?

También viendo esto en japonés con ciertos caracteres ...

Aquí hay una caja de arena de código que reproduce mi problema. Parece que está relacionado con las formas. Usar entradas directamente está bien.

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

Agregué algunos casos:
Usar el estado de reacción y las entradas simples está bien
El uso de estado de reacción, formas simples y entradas simples está bien
Estamos usando un componente de formulario basado en contexto que no funciona. Puede ser un problema relacionado con el contexto.

Problema resuelto: lo hice funcionar en codepen. Por alguna razón, pasar 'input' como un componente funcionó, al pasar (props) => No.

¿Alguien tiene una idea de cuál es la diferencia?

De hecho, también probé:

Trabajos

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

No funciona

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

Funciona curiosamente

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

Claramente, hay algo de magia aquí que no entiendo. 😕

¿Alguna actualización?

Parece causar un resultado incorrecto cuando IME está habilitado

e84721f3ec71a5ce043ef8290

Experimenté el mismo problema que @otakustay
Parece imposible admitir la entrada controlada con la entrada IME. He rastreado la secuencia de eventos hasta lo siguiente.

  1. El usuario escribe una letra, digamos w
  2. onChange se activa
  3. El estado se actualiza con un nuevo valor
  4. El nuevo valor se propaga hasta el input mediante el atributo value .
  5. La "composición" del IME se interrumpe en este punto.

    • Hay una cadena w en el elemento de entrada

    • También hay una cadena w separada almacenada en el búfer IME

  6. El usuario escribe otra letra, digamos a
  7. La cadena en la entrada a combina con la cadena del búfer IME para producir wwa .
  8. Repita los pasos del 1 al 7 para obtener un montón de caracteres duplicados.

He notado que el error solo ocurre si la entrada se vuelve a renderizar > 15 ms después del evento de composiciónUpdate después del siguiente repintado.

En este momento, mi única solución es alejarme de las entradas controladas.

Editar : Aquí hay una reproducción simple: https://jsfiddle.net/kbhg3xna/
Edit2 : aquí está mi solución hacky: https://jsfiddle.net/m792qtys/ cc: @otakustay

¿Alguna actualización sobre esto?

actualizar ??

¿Algún avance en esto?

Aturdido, me enfrenté a esta pregunta

Interesante, parece que el problema no es solo sobre el cambio de varias veces. Si no establecemosState entre onCompositionStart y onCompositionEnd , la reacción "controlará" el valor tal cual. Esta acción interrumpirá la composición. Eso significa que no obtendremos el evento onCompositionEnd ...... (Si me equivoco, mencióname por favor.) Pero solo podemos cambiar el estado inmediatamente (De lo contrario, tendremos que enfrentar el problema @ Knubie menciona). Una reproducción aquí (parece un componente "medio controlado"): https://gist.github.com/cpdyj/6567437d96c315e9162778c8efdfb6e8

Pero estoy tan sorprendido de que el problema no tenga solución durante cinco años 😢

@hellendag Creo que no deberíamos disparar onChange hasta que se confirme la cadena IME.

No creo que esta sea una solución válida, ya que un componente podría querer conocer la cadena IME "no confirmada", por ejemplo, para filtrar opciones en una lista a medida que el usuario escribe.

No estoy seguro de si el enfoque que utilizo en este otro hilo podría ayudar a quienes tienen este problema, pero aquí hay un enlace por si acaso: https://github.com/facebook/react/issues/13104#issuecomment -691393940

¿alguna actualización?

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