Jude Fernandes
Jude Fernandes

Reputation: 7517

Child component constructor called multiple times

I have a parent component which is a flat list which contains a header HeaderComponent. This HeaderComponent is a custom component that I have created which contains 2 child components of its own. Whenever i refresh the list, I am passing a boolean to the HeaderComponent as props which get passed onto its own children, I am doing this so I can check if each component needs to fetch new data or not. The problem is that whenever the parent refreshes and sets a new state the constructors of the child components get called everytime. Shouldn't the constructor be called only the first time the parent initializes and then all further calls involve calling the shouldComponentUpdate method of the children in order to see if it needs an update or not.

Parent component

_renderHeader = () => {
    return <HeaderComponent Items={this.state.Data} refresh={this.state.refresh}/>;
};

render() {
    console.log("TAG_RENDER render called " + this.state.refresh);
    return (
        <FlatList
            refreshing={this.state.refresh}
            onRefresh={() => {
                console.log("onRefresh");
                this.setState({
                    refresh: true
                }, () => {
                    this._fetchData();
                });
            }}
            ......


            ListHeaderComponent={() => this._renderHeader()}
            .......
        />
    );
}

Header Component

export default class HeaderComponent extends React.Component {

    constructor(props) {
        super(props);
        console.debug("HeaderComponent");
    }

    render() {
        return (
            <MainHeader Items={this.props.Items}/>
            <SubHeader refresh={this.props.refresh}/>
        );
    }

}  

The constructor of MainHeader and Subheader gets called whenever the parent component refreshes. Does this mean that it is creating new child components each time it refreshes because I can see the render of the children also being called multiple times.

Upvotes: 12

Views: 10856

Answers (3)

Aakanksha Sethi
Aakanksha Sethi

Reputation: 81

As correctly stated in the one of the answers , removing the strict mode fixes the issue. Coming to why it does that, its because the strict mode intentionally calls the 'render' method twice in order to detect potential problems.

React works in two phases:render and commit. Render phase checks and determines the new changes to be applied. And commit phase applies it.

Render phase lifecycle includes methods like : constructor, UNSAFE_componentWillMount,UNSAFE_componentWillReceiveProps, ...,render and few more.

The render phase is time consuming and is often broken into pieces to free up the browser. Render phase might be called multiple times before the commit phase(usually very fast). Since the render phase methods are called more than once, its important that none of those method have any problems or side effects.

Thus just in order to highlight the possible side effects to make them easy to spot, react explicitly double invoke the render phase methods.

You can read more about this on :https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects :)

Upvotes: 8

madhured
madhured

Reputation: 443

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

  • Class component constructor, render, and shouldComponentUpdate methods
  • Class component static getDerivedStateFromProps method
  • Function component bodies
  • State updater functions (the first argument to setState)
  • Functions passed to useState, useMemo, or useReducer

https://reactjs.org/docs/strict-mode.html

As stated in the site, Note: This only applies to development mode. Lifecycles will not be double-invoked in production mode.

Upvotes: 3

Control your index.js file. If you see <React.StrictMode>, you should change to <>. This is solved my problem.

It should be like:

ReactDOM.render(
  <>
    <App/>
  </>,
  document.getElementById('root')
);

Upvotes: 20

Related Questions