React-native: TextInput becomes slow after lots of typing

Created on 9 Jul 2018  路  64Comments  路  Source: facebook/react-native

Environment

$ react-native info
Environment:
  OS: Linux 4.9
  Node: 8.11.3
  Yarn: 1.7.0
  npm: 5.6.0
  Watchman: Not Found
  Xcode: N/A
  Android Studio: Not Found

Packages: (wanted => installed)
  react: 16.3.1 => 16.3.1
  react-native: 0.56.0 => 0.56.0 (*)

(*) In my test app, actually v0.55.4 plus the patch from #19645 . Others on #19126 report the same symptoms using v0.56.

Description

After typing a lot of text into a controlled TextInput, like ~500 char on a recent fast phone, we start dropping frames. It gets worse the more you type; at ~1000 char, we very frequently drop frames and the app looks noticeably laggy.

Reproducible Demo

The original repro is by @s-nel: https://github.com/s-nel/rn19126

Originally reported at https://github.com/facebook/react-native/issues/19126#issuecomment-402904164; more discussion in subsequent comments in that thread.

In particular, here's the video from that repro:
video

Here's a video by @s-nel on my test app, with this description:

Yes I can reproduce from [that repo] after typing for a couple minutes straight. I don't have to clear anything as the original bug description [in #19126] indicates. Here you can see my JS framerate drop to single digits from adding a few characters

image

Here's my description of replicating that repro, again in my test app:

I just tried again with my test app, on RN 0.55.4 + patch. If I type continuously for about 60 seconds -- maybe 400-500 characters, at a rough estimate (just gibberish, both thumbs constantly typing letters) -- then the perf overlay gets to about "10 dropped so far", and zero stutters. If I continue and get up to about 90 seconds, the "dropped" figure climbs faster, and the framerate (in "JS: __ fps") noticeably drops. At about 150 seconds (~1000 characters?), the "dropped" figure rapidly climbs past 200, and the framerate hangs out around 30.

Even at that point, it's still "0 stutters". And if I ignore the perf overlay and try typing normal text and watching it like I were using an app for real: it's a bit laggy, but doesn't make things feel unusable or outright broken, and I think most of the time I wouldn't even notice.

That was on a Pixel 2 XL; the numbers will probably vary with hardware.

Background from previous bug

This bug seems closely related to #19126; the repro steps and symptoms seem to be exactly the same, except quantitatively much less severe. (The original reports of #19126 describe clearing the input as part of the repro; I now think that was probably a red herring.)

The extreme symptoms of #19126 were absent in v0.54, introduced in v0.55, and fixed in v0.56 by #19645 . As I wrote when I figured out the cause of that (leading to the one-line fix in #19645):

[This buggy NaN comparison] means every text shadow node will create a CustomLetterSpacingSpan around its contents, even when the letterSpacing prop was never set. It must be that we're somehow ending up with large numbers of these shadow nodes -- that sounds like a bug in itself, but I guess it's normally low-impact -- and this condition is failing to prune them from causing a bunch of work here.

I think we're now looking at exactly that underlying bug. It may well have been present in v0.54 and earlier releases; I don't think we have any data on that. [EDIT: @piotrpazola finds [below](https://github.com/facebook/react-native/issues/20119#issuecomment-489081902) that the bug is present in v0.50, and absent in v0.49.]

I don't know anything more about what causes it; even the hypothesis that we're ending up with large numbers of text shadow nodes is just an inference from how it interacts with the line fixed in #19645. So, more debugging is required.

I don't expect to do that debugging myself, because these remaining symptoms are no longer one of the top issues in our own app. But I hope somebody else will!

Bug TextInput Regression Android Ran Commands

Most helpful comment

Updated labels and flagged this as a high priority. Hopefully we can get this fixed as soon as possible.

All 64 comments

馃憢 @gnprice thanks for the writeup, I've added a couple more tags that seem to be more related to the issue.

Sadly AFAIK the TextInput is an hard portion to work with, and currently there is a bit of bus factor in terms of devs that know how it works "deeply". So it may take some time before this get fixed, fingers crossed.

After few tests I`ve discovered that clean InputText (without any styling) works normally (sometimes fps going down, but app is not freezing). But if I add some styling to input (e.g. fontSize) then typing process is going to be laggy more and more.

Unstable behavior is appear much faster if quantity of styling options is more. It seems that something went wrong with styling span generation (size, lineHeight, letterSpace and so on) inside of the logic of the text shadow nodes code.

For now, i have to remove all styling from inputs, to get app works.

Maybe that helps someone. Cheers!

19500 - Same issue.

I am closing this issue because it does not appear to have been verified on the latest release, and there has been no followup in a while.

If you found this thread after encountering the same issue in the latest release, please feel free to create a new issue with up-to-date information by clicking here.

(ok ignore the bot)

Hi,

I'm experiencing the same problem with 3 separate react native apps under developpement.

I have conducted my small tests with the slightlyest modified basic App (but trying with "PureComponent" - see below) with the following versions :

  • 0.54.0
  • 0.55.x series
  • and the 0.56.1 version.

There are differences, but as far as I can tell, the behaviour is basically the same : performances drop after a couple of hundreds of typing (300 words / 1000 carateres). So, could this be inherent to react native &/or mobile dev ?

There are aggravating factors, though :

  • Maybe, as @alp1396 reported above, text styling is a "bug" amplifier, I haven' tried
  • With 0.55.x (not tested with 0.54 nor 0.56), when <TextInput onChange={this._onChange} value={this.state.value} /> is replaced by <TextInput onChangeText={this._onChange}>{this.state.value}</TextInput>, performances are dramatically decreased (but this is not "by the book" anyway). 0fp is reached after 500 caracters or so. ;
  • With no value={this.state.value} inside the TextInput component, it is much better. At 1200 caracters, it is still around 45-55fps, which is acceptable.

My projects must allow the user to compose large pieces of texts, so I guess I will keep an eye on it, and try various workarounds to mitigate it (unmount the component + no value={this.state.value} when admissible...).

Thanks a lot for any update on this issue.


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

export default class App extends React.PureComponent {

  constructor(props) {
    super(props)
    this.state = {
      label : ''
    }
  }

  _onChange = (label) => {
    this.setState({ label })
  }

  render() {
    return (
      <View style={styles.container}>
       <Text>Caracter count : {this.state.label.length}</Text>
        <Text>Word count : {this.state.label.split(' ').length}</Text>
        <TextInput 
          onChangeText={this._onChange}
          value={this.state.label}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

I don't know if this is in any way helpful, but I started dev-ing on an earlier RN version for my app (I think it might have been .53) and didn't notice the slowdown issue until after I had upgraded my RN version to .55 (and now also seeing it in .56). To wit, not 100% SURE it wasn't there back then, but it does make me wonder if something introduced in .54 might be causing the issue.

This issue started in 0.54 and still exists today. Any chat app that uses a text input that persists between messages becomes unusable after only a few minutes if chatting. I wish there was some way to get this fixed.

@stueynet a workaround for chat is to force React to unmount and remount on the text input when the user sends a message.

for me the solution was to do the following

https://snack.expo.io/@jerson/text-input-slow-fix

 _onChange = (label) => {
     if (this.timeoutUpdate) {
      clearTimeout(this.timeoutUpdate);
    }
    this.timeoutUpdate = setTimeout(() => {
      this.input.setNativeProps({
        text: label
      });
    }, 100);

    this.setState({ label })
  }

Any updates on that? Still reproducible in 0.57rc4. Just create a new react native project and use this simple App class:

export default class App extends Component<Props> {
    render() {
        return (
            <TextInput />
        );
    }
}

As the TextInput is unstyled, you won't see it, just click in the top left corner, then the cursor appears. After several recursions (3-5) of typing and clearing the whole text, the lag is noticable, from then on the lag increases every time you clear. On our test device, also other apps are slow then, e.g. the Chrome address bar lags just like the RN TextInput. Only a restart of the device fixes it, but it appears again after some recursions of typing and clearing.

OK I have been elbows deep in this issue for a week, I would not have considered myself strong on the Native code side of things, but I think I can at least confirm the original hypothesis that large numbers of spans are being created...

By attaching a breakpoint in /com/facebook/react/views/textinput/ReactEditText.class:395 (manageSpans() method) I can see that as the input is used the number of CustomLineHeight spans on it grows continuously, not being removed when the input is cleared or the text the span affects is deleted. From my understanding this could be other styling spans too - it just happens to be customLineHeight spans in my case because that is the styling I am using.

From what I can tell this is caused by the combination of a few things -

  1. The CustomLineHeight class is not one of the classes checked at the start of manageSpans() in:
      // Remove all styling spans we might have previously set
      if (ForegroundColorSpan.class.isInstance(spans[spanIdx]) ||
          BackgroundColorSpan.class.isInstance(spans[spanIdx]) ||
          AbsoluteSizeSpan.class.isInstance(spans[spanIdx]) ||
          CustomStyleSpan.class.isInstance(spans[spanIdx]) ||
          ReactTagSpan.class.isInstance(spans[spanIdx])) {
        getText().removeSpan(spans[spanIdx]);
      }
  1. Although in sameTextForSpan() it specifically checks to see if the span is for a section of text that no longer exists, and does not add the span to the new SpannableStringBuilder it is building to replace the existing text with, this doesn't help because...
  2. back in maybeSetText() we call getText().replace(0, length(), spannableStringBuilder); however this replaces the text spans from 0 to the new length, not the old one, leaving the spans related to deleted text alive and kicking.

I tried changing the second param to the previous length of the text, however unfortunately this makes the Editable throw and out of range exception as it already considers it's length to be that of the new text (Even though it is still hanging on to the references to the spans that run outside of that new text's bounds).

What did seem to help for me was to add CustomLineHeight as one of the classes to check for the removal of style spans. As above - this just happens to be the styling spans that I am using, but other use cases may need other span classes added there. Seeing as the span is being removed directly, rather than replaced, it seems to work out.

What this does not explain is the experiencing of this issue without clearing or deleting text - that I have no clue about - but certainly as per @netdesk and @stueynet above I was still seeing the performance issues after clearing text even after applying the patch from https://github.com/facebook/react-native/pull/19645 .

Hopefully this points someone with more knowledge of the Android TextInput code in the right direction

For me the only stable solution to avoid any lags is to use uncontrolled TextInput which means DON'T use value field. You can manage that in 2 ways:

  1. Use _lastNativeText...
addNewTodo = () => {
    const value = this.addTodoRef._lastNativeText

    if (value) {
        this.props.actions.addTodo(value)
    }
}

render() {
    <TextInput
        ref={component => { this.addTodoRef = component }}
        onSubmitEditing = {this.addNewTodo}
        blurOnSubmit
    />
}

but in this case this.addTodoRef.clear() and this.addTodoRef.setNativeProps({text: ''}) will not empty _lastNativeText, so this solution requires even more hacks above that

  1. Use onChangeText with class property
textInputValue = null

addNewTodo = () => {
    const value = this.textInputValue

    if (value) {
        this.props.actions.addTodo(value)
        this.addTodoRef.clear()
        this.textInputValue = null
    }
}

onChangeText = (text: string) => {
    this.textInputValue = text
}

render() {
    <TextInput
        ref={component => { this.addTodoRef = component }}
        onSubmitEditing = {this.addNewTodo}
        blurOnSubmit
        onChangeText={this.onChangeText}
    />
}

Thank you so much @sintylapse!!!!

So @gnprice can we confirm this is still not fixed even in 0.57 and the issue seems to be related to the value prop on the text input. Using the @sintylapse hack above the issue does not appear to be a problem. Perhaps this will help in terms of figuring out a solution?

To summarize 0.54 and 0.55 are essentially unusable on Android. 0.56 has a partial mitigation of the problem which lets you type for longer but likely will start to be problematic just after more typing.

Just a reminder - On iOS, TextInputRef.clear() is not working on v0.54. A check in Platform.OS is needed before applying the hack @sintylapse provided.
https://github.com/facebook/react-native/issues/18272

We did a lot of experimenting in the last days, and our issue is clearly linked to the Google Keyboard app. I don't know if it's the exact same issue like this one discussed here, because we could reproduce it down to RN 0.50 (simple app with just a TextInput like my example above). In 0.49 it was not reproducible, from 0.50 to 0.57rc4 we could reproduce it. In our current app in development an external keyboard is used, it's easier to reproduce then because you can hammer the physical keys, CTRL+A, Delete, hammer again, and repeat that a couple of times until it becomes slower and slower. We tried to reset our test devices, after reset the slowness was gone, until the Google Keyboard updated in the background from 4.* to 7.* - then the slowness immediately touched in. Downgrading Google Keyboard to 4.* or deactivating it totally fixes the issue immediately. We tried some other keyboards. With Swift keyboard it's slow too, there you see that our test device does hard work when updating swift's vocabulary suggestions, but it's usable and doesn't slow down with every cleaning of the input - it's just a bit slow from the beginning. Other keyboards like Chrooma or Go also introduce some slowness, but you only see it if you hammer the physical keys with flat hands and fingers, not if you type normally. With Google Keyboard 7.* enabled, it becomes slower and slower with every clearing of the TextInput. If you disable voice keyboard and then uninstall all keyboard apps, (you can't disable the voice keyboard when it's the only keyboard left so you have to disable it before you uninstall the last keyboard app), so, there is no software keyboard left, then there is zero slowness, nothing. Maybe it's not directly related to this issue, but at least the effect is the same.

@oe5wei You write a story?

Any updates on this issue? Really annoying bug :(

@piubellofelipe I'd recommend using @sintylapse's temporary solution until it's fixed. Graceful enough for me in the meantime!

Nothing change?

Same problem here. This Issue is from july... TextInput is a very ... very critical feature!

 React Native Environment Info:
    System:
      OS: macOS High Sierra 10.13.6
      CPU: x64 Intel(R) Core(TM) i5-4278U CPU @ 2.60GHz
      Memory: 88.79 MB / 16.00 GB
      Shell: 3.2.57 - /bin/bash
    Binaries:
      Node: 8.12.0 - /usr/local/bin/node
      npm: 6.4.1 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
    IDEs:
      Android Studio: 3.1 AI-173.4907809
      Xcode: 10.1/10B61 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.5.0 => 16.5.0 
      react-native: 0.57.0 => 0.57.0 
    npmGlobalPackages:
      create-react-native-app: 1.0.0
      react-native-cli: 2.0.1

AFAIK there is no PR directly related to this issue currently open, feel free to implement something if you can.

There are currently a lot of things going on with the repo, so I have no estimate on when this can be picked up.

0.57.7 still have this problem

For me the only stable solution to avoid any lags is to use uncontrolled TextInput which means DON'T use value field. You can manage that in 2 ways:

  1. Use _lastNativeText...
addNewTodo = () => {
    const value = this.addTodoRef._lastNativeText

    if (value) {
        this.props.actions.addTodo(value)
    }
}

render() {
    <TextInput
        ref={component => { this.addTodoRef = component }}
        onSubmitEditing = {this.addNewTodo}
        blurOnSubmit
    />
}

but in this case this.addTodoRef.clear() and this.addTodoRef.setNativeProps({text: ''}) will not empty _lastNativeText, so this solution requires even more hacks above that

  1. Use onChangeText with class property
textInputValue = null

addNewTodo = () => {
    const value = this.textInputValue

    if (value) {
        this.props.actions.addTodo(value)
        this.addTodoRef.clear()
        this.textInputValue = null
    }
}

onChangeText = (text: string) => {
    this.textInputValue = text
}

render() {
    <TextInput
        ref={component => { this.addTodoRef = component }}
        onSubmitEditing = {this.addNewTodo}
        blurOnSubmit
        onChangeText={this.onChangeText}
    />
}

This is a good way, but it will still slow down after a thousand edits.

demo gif link

Here is a demo

The above does not work(and should! because a standard-text-input should just work!). Please update main-readme with the following text: TEXT-INPUT DOES NOT WORK! Because THIS is a SHOWSTOPPER for any app but it takes some useless time debugging(and writing an entire app based on RN) to get it.

0.57.8 still have this problem. +1

For many reason we have to keep the version 0.55 for the app in my company , I tried to fix this issue with this workaround, I have a text input wich need to handle 20 chars then delete them and repeat it 500 times, so the lag is still there at the end.

Is it normal that I have to reload the device ? (even by closing the app the keyboard stay laggy).

Thanks.

It's odd that this video wasn't mentioned so far.
https://youtu.be/83ffAY-CmL4?t=1366

Of course this is a serious issue, but I think everyone should wait for the awesome work the core team is doing.

@oe5wei Thanks, we started to use an other keyboard and desactivate default google keyboard wich solved this issue.

0.58.6 - the problem persists.

Updated labels and flagged this as a high priority. Hopefully we can get this fixed as soon as possible.

For me the only stable solution to avoid any lags is to use uncontrolled TextInput which means DON'T use value field. You can manage that in 2 ways:

  1. Use _lastNativeText...
addNewTodo = () => {
    const value = this.addTodoRef._lastNativeText

    if (value) {
        this.props.actions.addTodo(value)
    }
}

render() {
    <TextInput
        ref={component => { this.addTodoRef = component }}
        onSubmitEditing = {this.addNewTodo}
        blurOnSubmit
    />
}

but in this case this.addTodoRef.clear() and this.addTodoRef.setNativeProps({text: ''}) will not empty _lastNativeText, so this solution requires even more hacks above that

  1. Use onChangeText with class property
textInputValue = null

addNewTodo = () => {
    const value = this.textInputValue

    if (value) {
        this.props.actions.addTodo(value)
        this.addTodoRef.clear()
        this.textInputValue = null
    }
}

onChangeText = (text: string) => {
    this.textInputValue = text
}

render() {
    <TextInput
        ref={component => { this.addTodoRef = component }}
        onSubmitEditing = {this.addNewTodo}
        blurOnSubmit
        onChangeText={this.onChangeText}
    />
}

I tried your solution. I see definite improvement, but text is getting appended when I use scanner for typing instead of keyboard .I am testing on Zebra MC 36 Android device which has inbuilt hardware scanner. I don't type using keyboard, instead i use the scanner for scanning QR Code/Barcode and the text gets inserted in TextInput wherever the cursor is placed,

Whenever I scan really fast,I see text getting appended.Suppose I scan 'A',then I scan 'B' really fast,I see 'AB' instead of 'B' inside the textinput

I am using uncontrolled component only.

Any solution ?

For me the only stable solution to avoid any lags is to use uncontrolled TextInput which means DON'T use value field. You can manage that in 2 ways:

  1. Use _lastNativeText...
addNewTodo = () => {
    const value = this.addTodoRef._lastNativeText

    if (value) {
        this.props.actions.addTodo(value)
    }
}

render() {
    <TextInput
        ref={component => { this.addTodoRef = component }}
        onSubmitEditing = {this.addNewTodo}
        blurOnSubmit
    />
}

but in this case this.addTodoRef.clear() and this.addTodoRef.setNativeProps({text: ''}) will not empty _lastNativeText, so this solution requires even more hacks above that

  1. Use onChangeText with class property
textInputValue = null

addNewTodo = () => {
    const value = this.textInputValue

    if (value) {
        this.props.actions.addTodo(value)
        this.addTodoRef.clear()
        this.textInputValue = null
    }
}

onChangeText = (text: string) => {
    this.textInputValue = text
}

render() {
    <TextInput
        ref={component => { this.addTodoRef = component }}
        onSubmitEditing = {this.addNewTodo}
        blurOnSubmit
        onChangeText={this.onChangeText}
    />
}

I tried your solution. I see definite improvement, but text is getting appended when I use scanner for typing instead of keyboard .I am testing on Zebra MC 36 Android device which has inbuilt hardware scanner. I don't type using keyboard, instead i use the scanner for scanning QR Code/Barcode and the text gets inserted in TextInput wherever the cursor is placed,

Whenever I scan really fast,I see text getting appended.Suppose I scan 'A',then I scan 'B' really fast,I see 'AB' instead of 'B' inside the textinput

I am using uncontrolled component only.

Any solution ?

If you only need to scan barcode (which mean all code are not just single word), you can think only if (newVal.length - value.length) > 1 is the next input from scanner, then emit your customs input component鈥檚 onChangeText event with old value and new value, and clear old. This works for me because I don鈥檛 need to consider the paste situation.

@LzxHahaha Actually these barcodes which are being scanned are not of fixed length,They can contain as many characters. Eg - Some barcodes may contain 10 characters and some may contain 15 characters and so on

This text getting appended is a serious problem for us.In my use case a person would be scanning approx 110 barcodes in 1 minute. Sometimes even three barcodes also get appended in textinput box before the texinput is cleared.

I.e I first scan 'A', then 'B', then 'C' very quickly. I see 'ABC' inside my textinput before it is cleared

Ideally I should see first 'A', then 'B', then 'C'

whats up guys? is there any official solution or fixing?

I've made bunch of tests with different RN versions and the explanation is the only one: from October 2017 the issue remains from RN 0.50. As I see in changelog there were lots of changes including TextInput and TextShadowNode. The code below works fine in RN 0.49.

state = {
      code: '',
      count: 0,
    }

  _scanCodeEndEditing = () => {
    let code=this.scanCodeInput._lastNativeText;
    let count=this.state.count+1;
    this.setState({
      code,
      count
    });
    this.scanCodeInput.clear();
    this.scanCodeInput.focus();
  }

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Test RN0.49 width 100
        </Text>
        <Text>{this.state.code}</Text>
        <Text>Count: {this.state.count}</Text>
        <TextInput
          style={{width: 100}}
          onEndEditing={this._scanCodeEndEditing}
          ref={input => { this.scanCodeInput = input }}
        />
      </View>
    );
  }

Downgrading my project is the only solution for me for now. I can make 20-30 scans in 1 minute by bluetooth HID interface scanner of datamatrix code including 50 chars per scan into the single inputtext and nothing get laggy. From RN0.50 is impossible to do this, it's getting laggy really hard from 6-8th scan so it's something around 300-400 chars sent and the device needs to be restarted, not only the app. Really annoying.

I think they are rewriting RN Core in order to have communication through the bridge less asynchronous - https://youtu.be/83ffAY-CmL4?t=1358 . Perhaps this will fix the issue

hey everyone, I'm sorry this issue is still around. As @sintylapse wrote about, the FB team is currently working on a rewrite of the RN architecture - you can find more details in the pinned issues in this library https://github.com/react-native-community/discussions-and-proposals/issues.

Anyway, this has been a fairly important issue - I'll try to raise it again with the FB team, maybe there is some intermediate step that can be taken to make the situation better.

In the meantime, the PR process flow has improved greatly in the past few months so if you have any tweaks that could help please submit a PR 馃

I've made bunch of tests with different RN versions and the explanation is the only one: from October 2017 the issue remains from RN 0.50. As I see in changelog there were lots of changes including TextInput and TextShadowNode. The code below works fine in RN 0.49.

@piotrpazola Cool, that is very helpful new information!

The next step, if you're (or anyone else is) up for trying it, would be to do the same thing with different RN versions between v0.49 and v0.50, from Git. The goal would be to pin down a single commit that introduced the issue. Then that will be a very powerful clue for diagnosing the issue -- that's exactly how I diagnosed and fixed the related issue #19126.

There are 306 commits in that range; so with the magic of binary search, you'll need to try 9 different versions (because 2^9 >= 306 > 2^8).

$ git rev-list --count v0.49.0..v0.50.0
306

Git has a handy utility git bisect that can help manage the binary search for you, or you can also just do it by hand. (Try it on the midpoint v0.50.0~153, etc.)

For running with an RN version from Git, see this page of docs:
https://facebook.github.io/react-native/docs/building-from-source.html

The next step, if you're (or anyone else is) up for trying it, would be to do the same thing with different RN versions between v0.49 and v0.50, from Git. The goal would be to pin down a single commit that introduced the issue. Then that will be a very powerful clue for diagnosing the issue -- that's exactly how I diagnosed and fixed the related issue #19126.

@gnprice Thank you for advices! I'm glad that it could help because it really makes me bad. If I get some extra time I'd build some middle versions of RN between 0.49 and 0.50 and I'll do the same tests. I spent some time digging in java code of TextInput and so on, comparing implementations of 0.49 and 0.50 versions. There were lots of changes and it's unclear what could went wrong. Hopefully, we've got the best chance to fix this that ever.

I spent some time digging in java code of TextInput and so on, comparing implementations of 0.49 and 0.50 versions. There were lots of changes and it's unclear what could went wrong.

Makes sense! Yeah, the powerful thing about git bisect (or doing the equivalent by hand) is that you can narrow it down to a much smaller diff, to go back and study in exactly that way.

Especially when a bug is something subtle, that can make a big difference because it lets you look much more closely (because there is less to look at)... and also, it gives you much more traction to start making logical inferences about what's going on, just like how in a scientific experiment you always try to change just one or a few variables at a time.

If I get some extra time I'd build some middle versions of RN between 0.49 and 0.50 and I'll do the same tests.

Great :smile:

Hi guys any update on this ? Is it fixed in 0.60 ? @kelset

No updates on my side - I think that probably in latest 0.60 with Hermes this may have been fixed but I have not tested it.

I have the same problem and look forward to the latest progress.

Anyone checked this bug in 0.61? Is it any better?

@kelset We are still hitting this issue on 0.60

I have upgraded our app to 62-rc-0 and this does not appear to be an issue on Android for me.

oh wow that's great to hear! It's probably related to the fact that @TheSavior re-wrote TextInput completely to use hooks... if anyone else can test with the RC1 and confirm it would be super helpful!

Wow, that would be exciting! But also scary. I tried to make sure there were no behavior changes when I rewrote it

But also scary. I tried to make sure there were no behavior changes when I rewrote it

Here's hoping you don't restore the previous behavior 馃槃

Perhaps what was changed is that there was previously many unneeded renders on each key press, while with hooks you somehow avoided that?

It also seems to be fixed on 0.61.5. Can anyone else confirm?

not 100% sure but seems it works good on 0.61.5, checked locally

That's great to hear! Given that we sort of have a 3-way confirmation on this not being an issue in latest versions, I'll be optimistic and close this issue.

If someone can repro this with latest 0.61.x AND 0.62 RC please link it below and we can reopen this.

I think closing this is a little premature. This is a major issue that has affected the entire user base for several years. This issue alone has caused several developers i know personally to abandon react native due to frustration and hundreds of hours of lost productivity. I think it deserves some more thorough testing. And if it is fixed, maybe we can find the commit that fixed it and the reason it was broken in case it turns up again in the future.

Given that 3 different developers confirmed separately that the issue is fixed for them I thought it would be good to close it to signal to the other developers in the issue that there has been "an evolution" on this subject (as probably many people don't open the notification about it when simply new comments are added).
But I see your point @rspenc29 so I'll reopen.

I think it deserves some more thorough testing. And if it is fixed, maybe we can find the commit that fixed it and the reason it was broken in case it turns up again in the future.

If you could help with that it would be great, as my bandwidth is quite limited.

Seems it's finally gone. Tested on 0.61.5 and it is working fine

Just tested on 0.62.0-rc.2 works perfect!!! TextInput now not freeze UI and onChangeText() setState() not lagging anymore, not need to make workaround like:
this.inputRef.current._lastNativeText;

Cool - thanks everyone. When 0.62.0 is out I'll close this then.

@kelset Are you sure?
I thought this was an architectural issue as mentioned by @axe-fb here: https://youtu.be/83ffAY-CmL4?t=1366

On 0.62 I am still experiencing the issue on real low end devices. In the emulator its fast. Is there a way I can provide more debugging info?

@kelset Are you sure?
I thought this was an architectural issue as mentioned by @axe-fb here: https://youtu.be/83ffAY-CmL4?t=1366

This is the current problem (slides from infinite-red video and the solution is from @nparashuram)

You type R and you set value of R to the field.

image

You add E to R (RE) and another call to onChangeText is triggered, at the same time callback setText('R') is called

image

and now setText('RE') is called again while the user keeps updating that field and adding callback that are slowing down the app

image

WORKAROUND from @nparashuram

Add a debounce function, that delays calling onChangeText every 100 milleseconds

image

SOLUTION from @nparashuram

The solution that he proposes at minutes 24:55 (for the new react-native versions) is to use syncronous calls instead of asyncronous.

You type R --> syncronous call setValue('R') --> you type E --> syncronous call setValue('RE')

image

image

https://formidable.com/blog/2019/fabric-turbomodules-part-3/

I am experiencing this issue on RN 0.63.2 and it appears to be exactly what @fabriziobertoglio1987 is pointing to. If I remove value then TextInput is super fast. Many users on Android 8/9 phones (a little old, but not walkie talkies) are reporting that it is buggy to use the TextInput.

I am using a workaround where I remove the value prop. I set a defaultValue and use onChangeText to listen to changes. This stops the bugginess since it doesn't have to make the round trip explained above.

Even in the react-native docs they mention this flicker (I guess) https://reactnative.dev/docs/textinput#value

value: The value to show for the text input. TextInput is a controlled component, which means the native value will be forced to match this value prop if provided. For most uses, this works great, but in some cases this may cause flickering

Has anyone had bad experiences from using defaultValue and onChangeText?

@wmonecke, we are considering using your technique. Did you find any drawbacks to it eventually?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

phongyewtong picture phongyewtong  路  3Comments

janmonschke picture janmonschke  路  3Comments

despairblue picture despairblue  路  3Comments

jlongster picture jlongster  路  3Comments

DreySkee picture DreySkee  路  3Comments