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

[TextInput] Error setting property 'text' of RCTTextField with tag #144: Native TextInput(Hdsgdh) is 4 events ahead of JS - try to make your JS faster. #4845

Closed
rclai opened this issue Dec 17, 2015 · 43 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@rclai
Copy link
Contributor

rclai commented Dec 17, 2015

This error happens when you type extremely fast. The more components you have alongside it, the more likely that this will happen.

<TextInput value={this.state.value} onChangeText={value => this.setState({ value })} />

And if you hit submit IMMEDIATELY after typing, the value won't be set and the input may just be blank.

In order for the value to actually be there, you have to wait just a little bit, then you can hit enter and the value will stay.

This is on iOS.

@facebook-github-bot
Copy link
Contributor

Hey rclai, thanks for reporting this issue!

React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.

  • If you don't know how to do something or not sure whether some behavior is expected or a bug, please ask on StackOverflow with the tag react-native or for more real time interactions, ask on Discord in the #react-native channel.
  • If this is a feature request or a bug that you would like to be fixed, please report it on Product Pains. It has a ranking feature that lets us focus on the most important issues the community is experiencing.
  • We welcome clear issues and PRs that are ready for in-depth discussion. Please provide screenshots where appropriate and always mention the version of React Native you're using. Thank you for your contributions!

@brentvatne
Copy link
Collaborator

setState must be expensive, can you re-create this issue with an example project that we can clone and try?

@tomauty
Copy link
Contributor

tomauty commented Jan 15, 2016

I believe it's due to creating a function for every re-render of TextInput. I know this is "old" in RN time, but try putting that function outside of the render function

@rclai
Copy link
Contributor Author

rclai commented Jan 15, 2016

I'll have to give that a try, thanks.

@rclai
Copy link
Contributor Author

rclai commented Feb 11, 2016

@tomauty you were right, putting the function outside made it perform faster and I didn't get the error when I typed really fast.

@someok
Copy link

someok commented May 3, 2016

My function outside, but I still meet this warn.

<TextFieldHolder withValue={hasText}>
                    <TextInput
                        ref="textInput"
                        placeholder={this.props.placeHolder}
                        style={[styles.valueText, this.props.textInputStyle]}
                        multiline={this.props.multiline}
                        value={this.state.text}
                        onFocus={this._setFocus}
                        onBlur={this._unsetFocus}
                        onChangeText={this._setText}
                        {...this.props.textInputProps}
                    />
                </TextFieldHolder>

@kristikristo
Copy link

My function is outside too, but I still meet the warnings. When I test it on the device, is really slow when I try to move to the next TextInput. Any solution yet?

@chandlervdw
Copy link

+1 — I'm also looking for a solution to this.

@tuxtux00
Copy link

tuxtux00 commented Jul 8, 2016

+1 - and me too

@stief510
Copy link

+1

1 similar comment
@kristojorg
Copy link

+1

@rclai
Copy link
Contributor Author

rclai commented Jul 13, 2016

@brentvatne is this a legitimate issue that deserves a Product Pains post because of all these accumulating +1s or is it just a matter of keeping your components light-weight so that re-renders don't cause this?

@wootwoot1234
Copy link

@tomauty thanks for the tip. That helped but didn't totally fix it.

Anyone else have a good work around?

The solutions I can think of are to pass the text value in the onBlur prop or add another prop that is like onChangeText but with some sort of delay so that it doesn't fire until the user takes a break from typing (or deleting).

@wootwoot1234
Copy link

I think this needs to be reopend.

@Brockify
Copy link

+1 I agree

@jpgarcia
Copy link

+1

3 similar comments
@jgkim
Copy link

jgkim commented Oct 13, 2016

+1

@nlively
Copy link

nlively commented Oct 23, 2016

+1

@dwilt
Copy link

dwilt commented Oct 25, 2016

+1

@dwilt
Copy link

dwilt commented Oct 25, 2016

For anyone looking for a workaround who doesn't need to constantly read the state of the text and only needs it on submission, I think I have one. I'm not sure this is reliable yet but it seems to work and definitely gets rid of the warning and the slowness.

The workaround is to remove the onChangeText all together and read from the input's _lastNativeText property off the ref: this.refs.input._lastNativeText.

For more details on what I did..

Here's what my original SearchInput.js input looked like:

render() {
    var { onSubmitEditing, onChangeText } = this.props;

    // ... edited for brevity 

    return (
        <View style={containerStyles}>
            <View style={styles.inputContainer}>
                <TextInput
                    ref="input"
                    onSubmitEditing={onSubmitEditing}
                    onChangeText={onChangeText}
                />  
            </View>
        </View>
    )
}

As suggested above, I was reading from the props directly above and it didn't work (not having an inline callback rendered every time). I also tried passing this.props.onChangeText directly to onChangeText instead of the destructuring like you're seeing above. I still had the warnings and shit performance like everyone else though. In my SearchInput container, I tried capturing the current text value in a class instance variable instead of the state to prevent additional re-renders as our UI didn't call for any immediate reaction to what was being typed:

class SearchInputContainer extends Component {

    constructor(props) {
        super(props);

        this.searchValue = '';
    }

    onSubmitEditing() {
        this._submit();
        this._startEditing();
    }
    _submit() {
        var { getSearchResults, searchResultsAreVisible } = this.props;
        var query = this.searchValue;

        if(!searchResultsAreVisible) {
            this._showSearchResults();
        }

        getSearchResults(query)
    }

    onChangeText(text) {
        this.searchValue = text;
    }

    render() {

        return (
            <SearchInput
                {...this.props}
                onSubmitEditing={this.onSubmitEditing.bind(this)}
                onChangeText={this.onChangeText.bind(this)}
            />
        )
    }
}

Note the this.searchValue = ''; in the constructor. Also note the onChangeText method that I was using to update it and that I was then reading that value when I fired the _submit method. I was pretty surprised that this had performance issues because I'm not re-rendering the state every time they typed. What was even odder though, was that when I first loaded my view with the search input on it, it was immediately slow before I had even started typing.

So, I removed the onChangeText handler, and tied into the onSubmitEnding callback and passed in the current value:

render() {
        var { onSubmitEditing } = this.props;

        var onSubmit = () => {
            var value = this.refs.input._lastNativeText;

            onSubmitEditing(value);
        };

        // ... edited for brevity 

        return (
            <View style={containerStyles}>
                <View style={styles.inputContainer}>
                    <TextInput
                        ref="input"
                        style={styles.input}
                        returnKeyType={returnKeyType}
                        onFocus={onFocus}
                        onBlur={onBlur}
                        onSubmitEditing={onSubmit}
                    />
                </View>
            </View>
        )
    }

Note the onSubmit method defined above and capturing the value of this.refs.input._lastNativeText and passing that into onSubmitEditing . Also note the removed onChangeText handler.

My updated container:

class SearchInputContainer extends Component {

    onSubmitEditing(query) {
        this._submit(query);
        this._startEditing();
    }

    _submit(query) {
        var { getSearchResults, searchResultsAreVisible } = this.props;

        if(!searchResultsAreVisible) {
            this._showSearchResults();
        }

        getSearchResults(query)
    }

    render() {

        return (
            <SearchInput
                {...this.props}
                onSubmitEditing={this.onSubmitEditing.bind(this)}
            />
        )
    }
}

Note how I'm passing in the query on onSubmitEnding instead of reading it from the instance variable and then passing that to submit.

@crobinson42
Copy link

I only experience this issue when I have remote debug live reload hot reload all turned on... If I turn them off, I no longer experience the issue.

@crobinson42
Copy link

Here's a repo to demonstrate the issue:

Bare bones ReactNative 0.33, redux, & react-redux example on a simple login form (only 1 component)

react-native-issue-808

@ajonno
Copy link

ajonno commented Nov 20, 2016

Im also seeing this issue, ONLY when live reload and debug remotely are both on. Im currently using RN version 0.37.0 (+ redux / react-redux)

@perrosnk
Copy link

+1

@avogel3
Copy link

avogel3 commented Nov 28, 2016

+1

Update: Can confirm what others have said. If I stop Debugging JS Remotely, the simulator speeds up dramatically and I no longer get the error. If I restart Debugging JS remotely, and the simulator slows again, I can fix it by closing then restarting the simulator itself.

@sarovin
Copy link

sarovin commented Nov 28, 2016

#10559

@perrosnk
Copy link

I fixed the problem by doing:

  1. Stop Remote JS Debugging and Disable Hot reloading
  2. Close Chrome window where the debugging is running
  3. Open a new Chrome window (not just new tab)
  4. Start Remote JS Debugging and Enable Hot reloading

I don't know what causes the problem, but in my case it appears when my mac resumes from sleep, with the simulator running.

@Choicelin
Copy link

the last few comments seems to associate with the performance of our simulator or mobile,I think it is the reason too.

@pitops
Copy link

pitops commented Mar 25, 2017

The problem is still there after all this time. Also what helped is close remote debugging

@JasonHenson
Copy link

JasonHenson commented Apr 21, 2017

I don't think trying to make your views faster, stopping debugging, etc. are real answers. I am working on an app that uses external barcode scanners and the scanner inputs text extremely fast, of which, I doubt any amount of optimization would help fix my issue. I even have this issue in release mode with barcode scanners. Why can it not just update in a delayed manner instead of just ignoring the input?

@MovingGifts
Copy link

@brentvatne I am still having this issue (so are many others in this thread) Is there a solution to this similar to what @JasonHenson suggested?

@brentvatne
Copy link
Collaborator

cc @sahrens who worked on this initially

@brentvatne brentvatne reopened this May 31, 2017
@PaulAndreRada
Copy link

PaulAndreRada commented Jul 16, 2017

It's definitely the live reload and remote debug in my case.
I tested it with the performance monitor on a text input while typing as fast as my little piggies could handle, my RAM moved from:

150MB to roughly 162MP when off.
150MB to a whopping 193MB when live reload and remote debug where on

@JasonHenson You might want to look into debounce and throttle. It's saved me a few times before.

@crobinson42 Thanks a million for that one.

@kravchuck-den
Copy link

kravchuck-den commented Jul 22, 2017

Hi all. I had the same problem, but I founded solution that works for me. The error is because we have a lot of setState in queue. So my solution is:

<TextInput
    onChangeText={text => {
        clearTimeout(this.textTimeout);
        this.textTimeout = setTimeout(()=>this.setState({phone: text}), 100);
    }}
/>

I define Timeout with 100 milliseconds delay (or you can pick any else, try to experiment with it), and on Each next call of "onChangeText" function I clear this timeout and define it again. So if you will type very quick, only your timeout will update, and after 100 milliseconds from your last type setState will update.

@pull-bot
Copy link

pull-bot commented Oct 9, 2017

Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:

  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the issue template.
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.

If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.

@hramos hramos added the Icebox label Oct 9, 2017
@hramos hramos closed this as completed Oct 9, 2017
@minhphung210
Copy link

same issues

@jayasimhaprasad
Copy link

I still continue to face this issue. I have a need to enable or disable a button based on if text input being empty or not.
AS @kravchuck-den pointed out this issue does not occur if i remove the setState. What is good way to handle view changes that are dependent on the text being empty or not ?

@jayasimhaprasad
Copy link

My requirement was to disable the button only when the text was empty. I put an if condition to call setState only of this condition turned true and it solved my problem.

@juliancorrea
Copy link

juliancorrea commented Mar 10, 2018

+1
Same issues. Debugging, Live Reload and Hot Reload Disabled.

1 similar comment
@yuyao110120
Copy link

+1
Same issues. Debugging, Live Reload and Hot Reload Disabled.

@12343954
Copy link

12343954 commented Apr 3, 2018

my solution is : use this.refs._txt_comment._lastNativeText

<TextInput ref='_txt_comment'
    style={styles.input_comment}
    multiline={true} maxLength={100}
    placeholder='评论'
    placeholderTextColor='gray'
    keyboardAppearance='dark'
    // value={this.state._txt_comment}    **// DO NOT Binding value**   <----- X
    onEndEditing={() => {
        // console.log(this.refs._txt_comment) 
        this.setState({ _txt_comment: this.refs._txt_comment._lastNativeText });                                                            
    }}
    // onChangeText={()=>{}}    **// DO NOT USE 'onChangeText'**   <----- X
/>

you can use this.refs._txt_comment._lastNativeText anywhere .
such as alert( this.refs._txt_comment._lastNativeText || '' ) in a button click event .

because , calling this.setState() so many times , and this.state has too many variables , it will show the Warning Native TextInput(xxx) is x events ahead of JS - try to make your JS faster.

NOTE:
1: first calling this.refs._txt_comment._lastNativeText without any typing, will return undefined
2: clear value

submit_comment = () => {
    alert(this.refs._txt_comment._lastNativeText || '');
    this.refs._txt_comment.clear();              // clear UI
    this.refs._txt_comment._lastNativeText = ''; // clear value
}

3: init value: not solved
this.refs._txt_comment._lastNativeText= new_value; // ok , but UI didn't update
i think, under MVVM idea, make it to a single component, so it can has its own state variables.

any good idea ? please tell me ! thank you !

@Abby3017
Copy link

Abby3017 commented Jul 6, 2018

I was also having that issue. But when I tried that on device instead of simulator it worked fine. No lag as shown in simulator. If you use debounce on the onChange function the lags that are coming up will be resolved. Take a cue from this article debounce example
Try that and if someone have better idea, please let us know.

@wzup
Copy link

wzup commented Sep 17, 2018

@crobinson42

I only experience this issue when I have remote debug live reload hot reload all turned on...

I have this issue even on real device! debug live reload hot reload doesn't matter here

@facebook facebook locked as resolved and limited conversation to collaborators Oct 9, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Oct 9, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests