FairyQueen
FairyQueen

Reputation: 2373

Why is componentWillReceiveProps() not waiting for setState() to finish?

I need my componentWillReceiveProps method in my child component SearchBar to wait on the setState() in it's parent's method hideSearchBar() to finish updating before it checks the props. Currently it hits inside of hideSearchBar() then hits componentWillReceiveProps() and performs the check then finally hits the console log in the callback function of the setState() change. How can I get the componentWillReceiveProps to wait on the setState() to fully finish updating first?

hideSearchBar(e) {
    this.setState({closeMenu: true}, () => {
        console.log('inside');
    });
}

render() {
    const {isLoading, products} = this.props.products;

    return (
        <TouchableWithoutFeedback onPress={(e) => this.hideSearchBar(e)} style={{zIndex: 0}}>
            <View style={styles.wrapper}>
                <Header/>
                <View style={styles.bodyWrapper}>
                    <ScrollView style={styles.scrollView}>
                        <ProductsContainer data={{productsList: { results: products }}}/>
                    </ScrollView>
                    <SearchBar closeMenu={this.state.closeMenu} resetCloseMenu={() => this.resetCloseMenu()} style={styles.searchBar} />
                </View>
                <Footer/>
            </View>
        </TouchableWithoutFeedback>
    );
}

Here is the componentWillReceiveProps() in SearchBar:

componentWillReceiveProps(nextProps) {
    if ((this.props != nextProps) && this.props.closeMenu) {
        this.closeMenu();
    }
}   

Upvotes: 0

Views: 272

Answers (2)

loelsonk
loelsonk

Reputation: 3598

Just small notice about your code implemetation.

componentWillReceiveProps(nextProps) {
    if ((this.props != nextProps) && this.props.closeMenu) {
        this.closeMenu();
    }
}

this.props != nextProps will always return false. Even though objects contain the same data they have different instances.

// See
const object1 = { a: 'b' };
const object2 = { a: 'b' };
const object3 = object1;

// returns false
console.log('is 1 equal 2', object1 === object2);
// returns false
console.log('is 1 equal 2', object2 === object3);

You could for example compare string this.props.message !== nextProps.message this would work.

But if you really need to compare objects, make sure your data is as shallow as possible and use shallowCompare function(lodash isEqual).

Comparing deep nasted objects might be too expensive.

You might be also interested in implementing React.PureComponent.

Upvotes: 0

Matt Aft
Matt Aft

Reputation: 8936

I think the problem is in your componentWillReceiveProps, you're checking this.props instead of nextProps, so that is probably evaluating to false and never running this.closeMenu().

try:

componentWillReceiveProps(nextProps) {
    if ((this.props != nextProps) && nextProps.closeMenu) {
        this.closeMenu();
    }
}   

Upvotes: 4

Related Questions