react-native: Possible bug with TextInput and Chinese input method on iOS

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

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 9
  • Comments: 36 (3 by maintainers)

Commits related to this issue

Most upvoted comments

Any Update on this issue? (exist in 0.55.4)

problem happened in react-native version 0.55.0

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

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.

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

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.

@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

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

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"
  /> 

problem happened in react-native version 0.54.2

so Big Issue!!!

@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

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

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

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

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.

@shergin Will do in 1-2 days. 👏