Pahlevi Fikri Auliya
Pahlevi Fikri Auliya

Reputation: 4527

How to early-fetch without waiting for all childrens to be mounted?

I have the following React component structure:

<A>
  <B>
    <C/>
  </B>
</A>

I fetch data in component A. Currently, I put the fetch logic in componentDidMount. But based on https://github.com/facebook/react/blob/v15.0.1/docs/docs/ref-03-component-specs.md#mounting-componentdidmount:

The componentDidMount() method of child components is invoked before that of parent components.

So, the fetching only happens after A, B, and C are mounted & rendered

Since in our case, A has deeply nested components, the fetching needs to wait all those components rendered and mounted.

Is there a way to do fetch earlier?

Upvotes: 4

Views: 160

Answers (3)

Jayavel
Jayavel

Reputation: 3407

The componentDidMount() method of child components is invoked before that of parent components.

While you're doing something asynchronous, show a loading spinner or something until all the info is fetched like below:

class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'React',
      data: [],
      isLoading: true
    };
  }

  componentDidMount() {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then(response => response.json())
      .then(data =>
        this.setState(() => {
          return { data , isLoading: false};
        })
      );
  }

  render() {
    if (this.state.isLoading) {
      return <p>Loading ...</p>; // initially isLoading is true, it renders a loading after fetch components will render
    }
    return (
      <div>
      <ul>
        {this.state.data.map(data => {
          return <li key={data.username}>{data.username} </li>
        })}
      </ul>
        <Hello name={this.state.name}>
          <p>
            Start editing to see some magic happen :)
          </p>
        </Hello>

      </div>
    );
  }
}

Demo

Upvotes: 1

Pahlevi Fikri Auliya
Pahlevi Fikri Auliya

Reputation: 4527

We managed to improve the performance, up to 2 second faster by following @Julien Bourdic and @Jayavel recommendation in the comment section above:

      state = {
        isReady: false
      }

      componentDidMount() {
        fetch();
        this.setState({ isReady: true });
      }

      render() {
        return this.state.isReady ? <Wrapped {...this.props} /> : null;
      }

Basically we render null when fetching is not finished. This way, component B and C won't be mounted & rendered, allowing A's componentDidMount (and fetch) to start earlier.

Upvotes: 1

Joru
Joru

Reputation: 4436

If you want to keep using React's lifecycle methods, a good option would be to not render the children of this component until componentDidMount is called and your data fetch is out. You could use setState to manage this.

Alternatively you could look into making data fetches outside of the React lifecycle. This can be a good option depending on what kind of state management solution you use and the general architecture of your app.

Upvotes: 0

Related Questions