React: Событие изменения запускается дополнительное время до завершения композиции IME

Созданный на 21 мая 2015  ·  48Комментарии  ·  Источник: facebook/react

Дополнительные детали

  • Аналогичное обсуждение с дополнительными деталями и анализом воспроизведения: https://github.com/facebook/react/issues/8683
  • Предыдущая попытка исправить это: https://github.com/facebook/react/pull/8438 (включает некоторые модульные тесты, но достаточно, чтобы быть уверенным в исправлении)

Оригинальный выпуск

Когда я пробовал этот пример из https://facebook.github.io/react/blog/2013/11/05/thinking-in-react.html , любые китайские символы, введенные методом ввода китайского пиньинь, запускали слишком много рендеров, например :

screen shot 2015-05-21 at 14 04 36

На самом деле я ожидал, что они не сработают, прежде чем я подтвердю китайский иероглиф.

Затем я попробовал другой метод ввода - метод ввода wubi, я получил следующее:

screen shot 2015-05-21 at 14 17 15

Это тоже странно. Итак, я провел тест в jQuery :

screen shot 2015-05-21 at 14 05 12

Только после того, как я нажму пробел для подтверждения символа, сработает событие keyup .

Я знаю, что это может отличаться между реализацией jQuery keyup и реакцией onChange , но я ожидал, что jQuery keyup обрабатывает китайские символы вместо того, чтобы реагировать на onChange .

Самый полезный комментарий

Привет, ребята из Facebook, на самом деле эта проблема вызывает СЕРЬЕЗНУЮ проблему: мы не можем обновлять ввод асинхронно с китайским вводом.
Например, мы не можем использовать метеорные реактивные источники данных или хранилища, такие как redux, потому что все они обновляются асинхронно.
Вот простейший пример, показывающий эту проблему, он использует setTimeout для асинхронного обновления:
https://jsfiddle.net/liyatang/bq6oss6z/1/

Я действительно надеюсь, что вы сможете исправить это быстро, и мы не будем тратить усилия на обходное решение здесь и там, снова и снова.

Благодарю.

Вот мой способ обхода . Если у кого-то возникнет такая же проблема, вы можете посмотреть

Все 48 Комментарий

cc @salier :) - Что нам здесь делать?

Я думаю, нам не следует запускать onChange пока строка IME не будет зафиксирована.

Один из способов справиться с этим в ChangeEventPlugin это игнорировать все события input между compositionstart и compositionend , а затем немедленно использовать событие input следующие compositionend .

Я провел небольшое тестирование на OSX Chrome и Firefox с упрощенным пиньинь и 2-Set Korean, и порядок событий и данные кажутся достаточно правильными. (Я предполагаю, что у нас будут проблемы с IE Korean, но нам может повезти.)

Я думаю, что мы можем продолжать сталкиваться с проблемами с альтернативными методами ввода, такими как расширение Google Input Tools, но для этого могут быть обходные пути.

Это также влияет на набор диалектических символов для латинских языков. Здесь не удается даже долгое нажатие e и последующее использование варианта.

Извините, это не связано. Мои извенения.

Есть ли обновление? Страдает тоже от этой проблемы.

В настоящее время нет - это не является для нас приоритетом прямо сейчас. Я был бы рад взглянуть на запрос на перенос, если кто-нибудь решит это исправить.

@salier Кажется, что IE не input после compositionend . Я тестировал IE11 и Edge в Windows 10. Он корректно запускается в Chrome и Firefox.

в ie 9 событие Change срабатывает слишком много раз при повторном вводе китайских символов

Привет, ребята из Facebook, на самом деле эта проблема вызывает СЕРЬЕЗНУЮ проблему: мы не можем обновлять ввод асинхронно с китайским вводом.
Например, мы не можем использовать метеорные реактивные источники данных или хранилища, такие как redux, потому что все они обновляются асинхронно.
Вот простейший пример, показывающий эту проблему, он использует setTimeout для асинхронного обновления:
https://jsfiddle.net/liyatang/bq6oss6z/1/

Я действительно надеюсь, что вы сможете исправить это быстро, и мы не будем тратить усилия на обходное решение здесь и там, снова и снова.

Благодарю.

Вот мой способ обхода . Если у кого-то возникнет такая же проблема, вы можете посмотреть

Я сделал простой пример для демонстрации того, как использовать события compositionstart и compositionend для предотвращения ввода китайского IME при проблеме onchange .
Вот ссылка: https://jsfiddle.net/eyesofkids/dcxvas28/8/

@eyesofkids хорошая работа, это можно сделать как реализацию по умолчанию onChange для ввода, textarea ...

хорошая работа !

Я столкнулся с той же проблемой, и @eyesofkids отлично работает (спасибо!).

После того, как обходной путь был на месте, я погрузился в исходный код React, чтобы хотя бы попытаться добавить для этого неудачный тест - надеясь позже добавить ожидаемое поведение в библиотеку - хотя это кажется немного сложным для тех, кто не знаком с внутренним устройством.

Первоначально я ожидал, что тест, аналогичный тому, что уже доступен для ChangeEventPlugin должен работать, то есть имитация собственного compositionStart / compositionUpdate и проверка отсутствия обратного вызова onChange уволен; также проверка onChange будет срабатывать только после моделирования compositionEnd . Однако, похоже, это не работает.

Следовательно, я подумал, что, возможно, проверка на ChangeEventPlugin.extractEvents() была бы осуществимым подходом, аналогичным тому, что было сделано в тестах для SelectEventPlugin . Здесь почему-то при извлечении событий всегда получаю undefined .
Для справки, это тестовый код, который я пробовал в _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);

Боюсь, я не знаю точно, как отлаживать эти тесты - иначе у меня было бы более четкое представление о том, что происходит. Любые инструкции о том, как действовать, или любые другие указатели будут очень признательны.

Обходной путь внезапно сломался в Chrome 53+, и кажется, что он больше не действует, потому что они изменили порядок запуска textInput , теперь после textInput . Как следствие этого, change не будет запущен, если он будет прерван во время композиции.

https://github.com/suhaotian/react-input может кому-то помочь

Для Chrome v53 есть хитрое решение. Для вызова handlechange после запуска compositionend .

handleComposition  = (event) => {

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

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

    } else{
      onComposition = true
    }
  }

проверьте демонстрацию здесь: https://jsfiddle.net/eyesofkids/dcxvas28/11/

@chenxsan вы нашли решение?
вы можете определить композицию Start и позволить переменной равняться true.
Затем, чтобы использовать переменную, которую вы установили, в onChange, чтобы увидеть, должен ли она запускать запрос

Я отправил новую проблему для контролируемых компонентов в № 8683

Временное решение для неконтролируемых и контролируемых компонентов (input, textarea) загружается в react-Compositionevent .

Давайте сделаем https://github.com/facebook/react/pull/8438 .

@yesmeck очень рад видеть эту новость.

Я видел, что тест был сосредоточен только на Webkit, он должен быть разделен на Chrome и Safari, потому что Chrome меняет порядок запуска события compositionend после 53+.

@eyesofkids Добавлен новый тестовый пример для Chrome до 53.

Чтобы подлить масла в огонь, я пытался обойти эту проблему и обнаружил, что текущая версия iOS safari не запускает событие compositionend при использовании японского IME Hiragana, я думаю, что это сделано намеренно, поскольку кажется, что меню композиции никогда не закрывается.
На @eyesofkids пример Временного решения InputValue никогда не обновляется, хотя для меня https://github.com/zhaoyao91/react-optimistic-input исправляет проблему с японской IME.

Для тех, кто ищет решение этой проблемы, вот готовый к использованию компонент. https://github.com/aprilandjan/react-starter/blob/test/search-input/src/components/SearchInput.js Просто используйте его вместо обычного элемента ввода текста, и все в порядке.

@ zhaoyao91 ваш обходной путь просто работает! большое спасибо.

Привет, ребята, какие новости в этом номере?

Это не было приоритетом, потому что слишком частое срабатывание onChange редко вызывает проблемы. Где это вызывает проблемы в вашем приложении?

@sophiebits, извините, случайно нажал «X». Это может снизить производительность, если в обработчиках событий изменения используются операции фильтрации или обратные вызовы сервера. Подход, показанный в https://github.com/facebook/react/issues/3926#issuecomment -316049951, является прекрасным обходным путем для неконтролируемых или собственных входов, но не соответствует управляемым входам React. Похоже, что некоторые в этой ветке пытались разработать PR, но обнаружили, что внутренности немного сложны - но, может быть, инженер в вашей команде сможет быстрее с этим справиться? https://github.com/facebook/react/issues/8683 - гораздо лучшее описание реальной проблемы IMO.

Может кто-нибудь, пожалуйста, помогите мне понять: проблема только в лишних onChange вызовах посередине ? Или в итоге получается неверное значение?

Тест из попытки исправления в https://github.com/facebook/react/pull/8438 проходит, если я удалю утверждение о количестве вызовов onChange . Поэтому я полагаю, что эта проблема касается только дополнительных вызовов onChange .

нет никаких дополнительных вызовов onChange, просто в конце получается неправильное значение, больше похоже на проблему onComposition.

@crochefluid Можете ли вы создать для этого неудачный тест? Подобно тому, что пытался сделать # 8438. В этом тесте неверного значения не было.

@gaearon Я попробую. Вы пробовали этот тест на сафари (Mac / IOS)?

Это тест Node, но он кодирует последовательности, полученные с разных браузеров и устройств. Пожалуйста, посмотрите его источник. Вам нужно будет добавить последовательности, которые не работают.

Поэтому я полагаю, что эта проблема касается только дополнительных вызовов onChange.

Точно.

У меня все еще возникает эта проблема. Похоже, что этот вопрос открыт уже 3 года, поддерживает ли React китайский ввод в контролируемые компоненты в настоящий момент?

Также вижу это на японском с определенными иероглифами ...

Вот песочница кода, которая воспроизводит мою проблему. Похоже, это связано с формами. Прямое использование входных данных - это нормально.

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

Я добавил несколько кейсов:
Можно использовать состояние реакции и простые входы
Использование состояния реакции, простых форм и простых входных данных - это нормально
Мы используем компонент формы на основе контекста, который не работает. Это может быть проблема, связанная с контекстом.

Проблема решена: он работает в коде. По какой-то причине передача 'input', когда компонент работал, при передаче (props) => не.

Кто-нибудь знает, в чем разница?

Собственно, я тоже пробовал:

Работает

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

Не работает

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

Работает как ни странно

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

Очевидно, здесь происходит какое-то волшебство, которого я не понимаю. 😕

Любые обновления?

Кажется, это приводит к неверному результату, когда включен IME

e84721f3ec71a5ce043ef8290

Я столкнулся с той же проблемой, что и @otakustay
Кажется невозможным поддерживать управляемый ввод с помощью ввода IME. Я проследил последовательность событий до следующего.

  1. Пользователь вводит письмо, например w
  2. onChange запускается
  3. Состояние обновлено с новым значением
  4. Новое значение распространяется до input помощью атрибута value .
  5. «Состав» IME на этом прерывается

    • Во входном элементе есть строка w

    • В буфере IME также хранится отдельная строка w

  6. Пользователь вводит другую букву, например a
  7. Строка во входном файле a объединяется со строкой буфера IME для получения wwa .
  8. Повторите шаги 1-7, чтобы получить кучу повторяющихся символов.

Я заметил, что ошибка возникает только в том случае, если ввод повторно отображается через > 15 мс после события CompositionUpdate после следующей перерисовки.

Сейчас мое единственное решение - отказаться от контролируемых входов.

Изменить : вот простое воспроизведение: https://jsfiddle.net/kbhg3xna/
Edit2 : Вот мой хакерский обходной путь: https://jsfiddle.net/m792qtys/ cc: @otakustay

Есть обновления по этому поводу?

Обновить ??

Есть новости по этому поводу?

Ошеломленный, я столкнулся с этим вопросом

Интересно, выглядит проблема не только в многократном onChange. Если мы не установим состояние между onCompositionStart и onCompositionEnd , реакция будет "контролировать" значение как есть. Это действие прервет композицию. Это означает, что мы не получим событие onCompositionEnd ...... (Если я ошибаюсь, упомяните меня, пожалуйста.) Но мы можем изменить состояние только немедленно (в противном случае нам придется столкнуться с проблемой @ Knubie упоминает). Репродукция здесь (выглядит как "полууправляемый" компонент): https://gist.github.com/cpdyj/6567437d96c315e9162778c8efdfb6e8

Но я так удивлен, что проблема не решена за пять лет 😢

@hellendag Я думаю, что мы не должны запускать onChange, пока строка IME не будет зафиксирована.

Я не думаю, что это подходящее решение, поскольку компоненту может понадобиться знать «незафиксированную» строку IME, например, для параметров фильтрации в списке по типам пользователей.

Я не уверен, что подход, который я использую в этом другом потоке, может помочь тем, кто сталкивается с этой проблемой, но вот ссылка на всякий случай: https://github.com/facebook/react/issues/13104#issuecomment -691393940

любые обновления?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги