Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible bug with TextInput and Chinese input method on iOS #12599

Closed
Kulbear opened this issue Feb 27, 2017 · 36 comments
Closed

Possible bug with TextInput and Chinese input method on iOS #12599

Kulbear opened this issue Feb 27, 2017 · 36 comments
Assignees
Labels
Component: TextInput Related to the TextInput component. Platform: iOS iOS applications. Ran Commands One of our bots successfully processed a command. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@Kulbear
Copy link

Kulbear commented Feb 27, 2017

Description

I have some TextInput components in my project and there should be some problems with onEndEditting and onBlur props of TextInput component. If I make the TextInput blur before I confirm the entered content from the Chinese input method, all the changes I made during this round of focus will be lost. Check the video below, starts from 0:17, the video demonstrates the issue.

Basically, it should be an issue between the system Chinese input method and the RN TextInput component. I made a 30-second video record to demonstrate this issue.

https://www.youtube.com/watch?v=BG0WNHW2MEc

repro

repro2

Reproduction

I don't know how to work with Chinese input methods on rnplay, so I've pushed a sample project with minimal code for reproduction.

Current code with a workaround

Original bug reproduction

I created a new project. The only modified file is the index.ios.js

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  TextInput,
  View
} from 'react-native';

export default class ChineseTextInputIssue extends Component {
  constructor (props) {
    super(props);
    this.state = {
      text: ''
    };
  }

  render () {
    return (
      <View style={styles.container}>
        <TextInput
          style={styles.inputField}
          placeholder="Type here to translate!"
          value={this.state.text}
          onBlur={(evt) => console.log('onBlur event:', evt.nativeEvent.text)}
          onChange={(evt) => console.log('onChange event:', evt.nativeEvent.text)}
          onChangeText={(text) => this.setState({ text })}
          onSubmitEditing={(evt) => console.log('onSubmitEditing event:', evt.nativeEvent.text)}
          onEndEditing={(evt) => console.log('onEndEditing event:', evt.nativeEvent.text)} />
        <Text style={styles.previewText}>
          {this.state.text}
        </Text>
        <TextInput style={styles.inputField} placeholder="Another to focus, meaningless" />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF'
  },
  inputField: {
    margin: 30,
    height: 50
  },
  previewText: {
    padding: 10,
    fontSize: 42
  }
});

AppRegistry.registerComponent('ChineseTextInputIssue', () => ChineseTextInputIssue);

Solution

As you can see from the video, the displayed text and the text in the TextInput component should be identical.

Additional Information

  • React Native version: 0.41.2
  • Platform: iOS, not tested on Android
  • Operating System: macOS 10.12.3
@Kulbear
Copy link
Author

Kulbear commented Feb 28, 2017

Note that this is no longer valid, it only works on React Native version: 0.41.2.
Pay attention to the last updated date before you downvote a comment.

I'll give a workaround which can fix the problem with both my original project and this reproduction project. The only modified part is inside the render() method. Check it below

render () {
  return (
    <View style={styles.container}>
      <TextInput
        style={styles.inputField}
        value={this.state.text}
        placeholder="Type here to translate!"
        onChange={(evt) => this.setState({ text: evt.nativeEvent.text })}
        onChangeText={(text) => setTimeout(() => {this.setState({ text: text })})}
        onEndEditing={(evt) => this.setState({ text: evt.nativeEvent.text })} />
      <Text style={styles.previewText}>
        {this.state.text}
      </Text>
      <TextInput
        style={styles.inputField}
        placeholder="Another to focus, meaningless" />
    </View>
  );
}

Basically, setTimeout did the trick but I am not sure why. And I think the bug I mentioned in this issue is still worth to figure out and fix.

repro3

If you want to make your app looks like not allow Chinese input method, you can remove this line onChange={(evt) => this.setState({ text: evt.nativeEvent.text })}. It will look like this:

repro4

Though I don't think this is a good idea, just FYI.

@Proudmoor
Copy link

Proudmoor commented Mar 1, 2017

@Kulbear I have the same problem , this should be a bug , and thanks for the workaround you provided.

@shergin
Copy link
Contributor

shergin commented Mar 16, 2017

Could you please confirm that this issue still exists in current master? We recently fixed very similar issue and I hope that fix may help with this problem as well.

@shergin shergin added the Platform: iOS iOS applications. label Mar 16, 2017
@Kulbear
Copy link
Author

Kulbear commented Mar 16, 2017

@shergin Will do in 1-2 days. 👏

@Kulbear
Copy link
Author

Kulbear commented Mar 16, 2017

@shergin With the dependencies below, it still doesn't work as expected.

"dependencies": {
    "react": "~16.0.0-alpha.3",
    "react-native": "github:facebook/react-native#d5dda1b1365321c0bb64eca0d1d88909f0f6c7fd"
}

repro5

@Swordsman-Inaction
Copy link
Contributor

@shergin
I dug for a while. Here is how the issue happens:

  • Enter some random word
  • Click outside of the TextInput
  • The textFieldDidChange gets called twice immediately, _nativeEventCount is increased by 2.
  • The _onChange gets called immediately.
  • this._inputRef.setNativeProps in _onChange is supposed to set native prop _mostRecentEventCount before the text is rendered, but somehow it didn't.
  • So the eventLag is larger than 0, and the correct text could not be set.(Even thought the native UITextField's text shouldn't be wrong I think).
  • Shit happens....

Here is the log I got from both side:

  • iOS
TextChange -> 196
setText -> count: 196 ; recentCount: 196, text: f
TextChange -> 197
setText -> count: 197 ; recentCount: 197, text: f g
TextChange -> 198
TextChange -> 199
setText -> count: 199 ; recentCount: 197, text: fg
setText -> count: 199 ; recentCount: 198, text: fg
  • RN:
receivedCount: 196
received text:f
render
receivedCount: 197
received text:f g
render
receivedCount: 198
received text:fg
render
receivedCount: 199
received text:fg
render
render

The count 198 and 199 is those two change after click the outside of the TextInput.
We can see that 198 is not set to native when the correct setText is called, maybe it's delayed for some reason I don't know.

I cannot dig deeper since I'm not familiar with iOS(I'm an Android developer), but there are two things I don't understand:

  • Why textFieldDidChange is called twice while using Chinese Keyboard? It won't be called while using English Keyboard.
  • Why is native prop mostRecentEventCount not set before the text is set in _onChange? Normal it does.

@Swordsman-Inaction
Copy link
Contributor

A simple tmp workaround is remove the condition about eventLag, using if ( ![text isEqualToString:self.text]) instead of if (eventLag == 0 && ![text isEqualToString:self.text]) in here

But it will cause the UI syc problem when your JS running slowly, be careful if you want to use the approach.

@shergin shergin self-assigned this Mar 16, 2017
Kulbear referenced this issue May 23, 2017
Summary:
This introduces event counts to make sure JS doesn't set out of date values on
native text inputs, which can cause dropped characters and can mess with
autocomplete, and obviates the need for the input buffering which added lag and
complexity to the component.  Made sure to test simulated super-slow JS text
event processing to make sure characters aren't dropped, as well as typing
obviously correctable words and making sure autocomplete works as expected.

TextInput is now a controlled input by default without causing any issues for
most cases, so I removed the `controlled` prop.

Fixes selection state jumping by restoring it after setting new text values, so
highlighting the middle of some text in the new ReWrite example and hitting
space will replace that selection with an underscore and keep the cursor at a
sensible position as expected, instead of jumping to the end.

Ads `maxLength` prop to support the most commonly needed syncronous behavior:
preventing the user from typing too many characters.  It can also be used to
prevent users from continuing to type after entering special characters by
changing it to the current length after a regex match.  Made sure to verify it
works well with pasted input (including in the middle of existing text),
truncating it and collapsing the selection the same way it does on the web.

Fixes bug in TextEventsExample where it wouldn't show the submit and end events,
even though there were firing correctly.
@ethanyanjiali
Copy link

I'm having a same issue with iOS system Chinese input on TextInput.

@kidmysoul
Copy link

kidmysoul commented Jul 30, 2017

Have the same problem in japanese input(also in chinese input). Only in IOS

when typing, only the first character is correctly spelled (example: ba→ば) but the rest characters donot work (example : ba→bあ)

when I use the setTimeout solution, I even cannot correctly input the first character. that solution does not work for me.(and I' m using redux-form Field to wrap the TextInput element)

Finnally I delete the redux-form,not use it and the TextInput get worked again.

@Kulbear
Copy link
Author

Kulbear commented Jul 30, 2017

@kidmysoul My workaround seems to be invalid after several releases since I made the original post... I think this problem will happen whenever we are using an input method like Chinese or Japanese input methods that require a selection after typing some character combination...

@honeyjie
Copy link

我也遇到同样的问题,不能输入中文。。。

@stale
Copy link

stale bot commented Oct 15, 2017

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. If you think this issue should definitely remain open, please let us know why. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Oct 15, 2017
@Kulbear
Copy link
Author

Kulbear commented Oct 15, 2017

This is still a problem for Chinese/Japanese/Korean input method.

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Oct 15, 2017
@stale
Copy link

stale bot commented Dec 14, 2017

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. If you think this issue should definitely remain open, please let us know why. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 14, 2017
@wlwg
Copy link

wlwg commented Dec 14, 2017

I’m having this problem of using TextInput with Chinese Pinyin probably due to the same bug. When I set a max length in the textinput and type Pinyin in this input, the length constraint applies to the Pinyin rather than the final resulting Chinese characters.

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 14, 2017
@stale
Copy link

stale bot commented Feb 12, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. If you think this issue should definitely remain open, please let us know why. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Feb 12, 2018
@Kulbear
Copy link
Author

Kulbear commented Feb 13, 2018

I think this issue could potentially affect a lot of Chinese, Korean, Japanese users, or say non-alphabetic language users.

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Feb 13, 2018
@kidmysoul
Copy link

Hey, when I update react native to version 0.54.0 ,this problem appears again !?

liked there were lots of changes about textinput in ios in 0.54.0 and maybe that effects.

<TextInput style={styles.title} onChangeText={this.onTitleChange} maxLength={100} placeholder="例....." underlineColorAndroid={'transparent'} value={title}/>

this simple code above cannot even input a whole Japanese word in ios.

@jiangbophd
Copy link

so Big Issue!!!!!

@react-native-bot react-native-bot added Ran Commands One of our bots successfully processed a command. Component: TextInput Related to the TextInput component. labels Mar 16, 2018
@feng-zhang0712
Copy link

problem happened in react-native version 0.55.0

@gelove
Copy link

gelove commented Apr 9, 2018

problem happened in react-native version 0.54.2

@feng-zhang0712
Copy link

@gelove Problem has been solved here #18456, the code has not been merged to newest version, so you have to modify your code manually https://github.com/facebook/react-native/pull/18456/files

@AKACC
Copy link

AKACC commented May 31, 2018

I took out value from Textinput and then the problem fixed. It seems every letter typed would trigger onChangeText and render again. Wish this can help.

@ankur-sardar
Copy link

ankur-sardar commented Jun 12, 2018

Any Update on this issue? (exist in 0.55.4)

@lzxb
Copy link

lzxb commented Jul 13, 2018

I also have the same problem, the version is 0.55.4

@daskinnyman
Copy link

this problem still occurs in 55.3

@wujunchuan
Copy link

wujunchuan commented Jul 16, 2018

I have to use the onEndEditing callback to replace the onChange callback.
But it won't be excuted timely

<TextInput
  style={[ commonStyles.commonInput, commonStyles.pdl_normal, commonStyles.pdr_normal ]}
  underlineColorAndroid={'transparent'}
  // 中文支持问题, issues
  // https://github.com/facebook/react-native/issues/12599
  // value={this.state.remark}
  // onChangeText={( text ) => this.setState( { remark: text } )}
  // onChange={(evt) => this.setState({ remark: evt.nativeEvent.text })}
  // onChangeText={(text) => setTimeout(() => {this.setState({ remark: text })})}
  onEndEditing={(evt) => this.setState({ remark: evt.nativeEvent.text })}
  placeholder={I18n.t( Keys.eos_remark )}
  defaultValue={this.state.remark}
  autoCapitalize={'none'}/>

Notice:
sometimes onEndEditing callback will not trigger, because the Blur Event doesn't trigger.
So, It is not the best solution

@Taphood
Copy link

Taphood commented Aug 2, 2018

This problem still occurs in RN56.0 as well.

As AKACC mentioned if you remove "value" field from TextInput it seems to work even if you use maxlength and onChangeText for every letter typed.

Since it is pretty common to read a value stored in Redux store as below I wish this bug to be taken care for CJK letters input.

 <TextInput
    value={this.props.displayName}       // <--- remove this line
    label="some_text"
    onChangeText={val=> this.onChangeInput("displayName", val)}
    maxLength={8}
    placeholder="some_placeholder_text"
    autoCapitalize="none"
  /> 

@xuechinahb
Copy link

This bug has been fixed. https://github.com/facebook/react-native/pull/18456/files. I merge this code manually, it works well.

@hkung77
Copy link

hkung77 commented Sep 3, 2018

Can I get some idea on when and/or which release will have the bug fix?

@kidmysoul
Copy link

@hkung77 maybe 0.57.0
and the 0.57.0-rc has already fixed this bug. you can use it too.

@elanpang
Copy link

elanpang commented Sep 12, 2018

This critical issue lived so long time even in 0.56.1, I can't understand.

@StevenMasini
Copy link

@elanpang this has been included in 0.57, see the changelogs

@elanpang
Copy link

@StevenMasini So luck :)

@stale
Copy link

stale bot commented Dec 21, 2018

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 21, 2018
@stale
Copy link

stale bot commented Dec 28, 2018

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.

@stale stale bot closed this as completed Dec 28, 2018
@facebook facebook locked as resolved and limited conversation to collaborators Dec 29, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Component: TextInput Related to the TextInput component. Platform: iOS iOS applications. Ran Commands One of our bots successfully processed a command. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests