React: 在IME合成结束之前,Change事件会额外触发

创建于 2015-05-21  ·  48评论  ·  资料来源: facebook/react

额外细节

  • 类似的讨论,带有更多细节和复制分析: https :
  • 先前对其进行修复的尝试: https :

原始发行

当我尝试从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处理中文字符而不是React的onChange

DOM Bug

最有用的评论

您好,Facebook人士,实际上,这个问题导致了一个严重的问题:我们不能与中文输入异步更新输入。
例如,我们不能使用流星反应性数据源或像redux这样的存储,因为它们所有反馈都是异步更新的。
这是显示此问题的最简单示例,它使用setTimeout进行异步更新:
https://jsfiddle.net/liyatang/bq6oss6z/1/

我真的希望您能迅速解决此问题,以便我们不会浪费精力在此反复进行解决。

谢谢。

这是我的解决方法。 如果有人遇到同样的问题,可以看看

所有48条评论

cc @salier :) –我们在这里应该做什么?

我认为在提交IME字符串之前,我们不应该触发onChange

ChangeEventPlugin处理此问题的一种方法是忽略compositionstartcompositionend之间的所有input事件,然后立即使用input事件以下compositionend

我在OSX Chrome和Firefox上使用简化的拼音和2套韩文进行了一些快速测试,事件顺序和数据似乎足够正确。 (我预言我们将在IE Korean中遇到问题,但我们可能会很幸运。)

我认为我们可能会继续看到其他输入法(例如Google输入工具扩展)的问题,但是可能有解决方法。

这也影响拉丁语言的辩证字符键入方式。 即使长按e然后使用variant在这里也失败。

抱歉,这似乎无关。 我很抱歉。

有没有更新? 也遭受这个问题。

目前没有任何人-这对我们而言不是当前的重中之重。 如果有人愿意解决此问题,我很乐意查看请求请求。

@salier似乎IE在compositionend之后不会触发input事件。 我已经在Windows 10的IE11和Edge上进行了测试,可以在Chrome和Firefox中正常启动。

在ie 9中,再次输入汉字时,更改事件触发太多次

您好,Facebook人士,实际上,这个问题导致了一个严重的问题:我们不能与中文输入异步更新输入。
例如,我们不能使用流星反应性数据源或像redux这样的存储,因为它们所有反馈都是异步更新的。
这是显示此问题的最简单示例,它使用setTimeout进行异步更新:
https://jsfiddle.net/liyatang/bq6oss6z/1/

我真的希望您能迅速解决此问题,以便我们不会浪费精力在此反复进行解决。

谢谢。

这是我的解决方法。 如果有人遇到同样的问题,可以看看

我做了一个简单的示例来演示如何使用compositionstartcompositionend事件来防止在onchange事件问题上输入中文IME。
这是链接: https :

@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+中突然中断,似乎不再有效,因为他们更改了触发compositionend的顺序:以前是在textInput之前发生的,现在在textInput 。 因此,如果在组合😕中中止change不会被解雇。

Chrome v53有一个棘手的解决方案。 在compositionend被触发后调用handleChange。

handleComposition  = (event) => {

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

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

    } else{
      onComposition = true
    }
  }

在此处查看演示: https :

@chenxsan找出解决方案了吗?
您可以检测到compositionStart并使变量等于true。
然后使用您在onChange设置的变量来查看它是否应该触发查询

我已经提交了关于#8683中受控组件的新问题

不受控制和受控制的组件(输入,文本区域)的临时解决方案上传到react-compositionevent

@yesmeck很高兴看到这个消息。

我看到测试只针对Webkit,应该将它分为Chrome和Safari,因为Chrome在53+之后更改了compositionend事件触发顺序。

@eyesofkids在53以下为Chrome添加了新的测试用例。

只是为了加油,我一直在尝试解决此问题,发现使用日语的平假名IME时,当前版本的iOS Safari浏览器不会触发compositionend事件,我认为这是故意的,因为合成菜单似乎从未关闭过。
@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通话中出现? 还是最终得到不正确的价值?

如果我删除有关调用onChange的次数的断言,则来自https://github.com/facebook/react/pull/8438中的修复尝试的测试将通过。 所以我想这个问题只是关于额外的onChange调用。

没有多余的onChange调用,它只是在最后获得不正确的值,似乎更像是onComposition问题。

@crochefluid您可以为此创建失败的测试吗? 与#8438尝试执行的操作类似。 在该测试中,没有错误的值。

@gaearon我要试试看。 您是否在Safari(mac / IOS)上尝试了该测试?

这是一个Node测试,但它编码从不同浏览器和设备捕获的序列。 请查看其来源。 您需要添加失败的序列。

因此,我想这个问题仅与额外的onChange调用有关。

究竟。

我仍然遇到这个问题。 看来这个问题已经开放了三年了,React目前是否支持中文输入受控组件?

在日语中也看到某些字符...

这是一个重现我的问题的代码沙箱。 看起来与表单有关。 直接使用输入即可。

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

我添加了一些案例:
使用反应状态和普通输入就可以了
使用反应状态,简单形式和简单输入
我们正在使用无法使用的基于上下文的表单组件。 这可能是与上下文相关的问题。

解决的问题:我在Codepen中工作。 由于某些原因,在传递(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. 新值通过value属性传播到input
  5. 输入法“合成”此时被中断

    • 输入元素中有一个w字符串

    • IME缓冲区中还存储了一个单独的w字符串

  6. 用户键入另一个字母,例如a
  7. 输入a的字符串与IME缓冲区的字符串组合以产生wwa
  8. 重复步骤1-7,以获得一堆重复的字符。

我注意到,仅当输入在下一次重画后的compositionUpdate事件之后重新渲染

现在,我唯一的解决方案是放弃受控输入。

编辑:这是一个简单的复制品: https :
Edit2 :这是我的hacky解决方法: https : //jsfiddle.net/m792qtys/ cc:

有任何更新吗?

更新??

这事有进一步更新吗?

惊呆了,我遇到了这个问题

有趣的是,看起来问题不仅在于多次onChange。 如果我们不在onCompositionStartonCompositionEnd ,则react将按原样“控制”该值。 此操作将中断合成。 这意味着我们将不会获得onCompositionEnd事件……(如果我打错了,请提及我。)但是我们只能立即更改状态(否则我们将不得不面对问题@ knubie提及)。 此处的复制品(看起来像一个“半受控”组件): https :

但是我很惊讶这个问题在五年内没有解决😢

@hellendag我认为我们不应该在提交IME字符串之前触发onChange。

我认为这不是一个有效的解决方案,因为组件可能想知道“未提交的” IME字符串,例如,当用户键入内容时,将列表中的选项过滤掉。

我不确定我在其他线程中使用的方法是否可以帮助解决此问题的人员,但以下链接仅供参考: https :

任何更新?

此页面是否有帮助?
0 / 5 - 0 等级