1

I'm having trouble understanding how the lifecycle hooks work in my React application. I have an application in which I pass some props to my Pagination component in my render method like so:

<Pagination
  totalRecords={this.state.blogPosts.length}
  pageLimit={5}
  pageNeighbours={2}
  onPageChanged={() => {console.log('page changed');}}
/>

In the Pagination constructor, I print out the prop values.

const { totalRecords = null, pageLimit = 30, pageNeighbours = 0 } = props;
console.log('totalRecords=', totalRecords); 

It prints out 0.

Fair enough, I haven't fetched my blog posts yet. So in componentDidMount, I fetch the blog posts like so:

componentDidMount() {
  axios.get('/blogs').then(
    response => {
      if (response.data) {
        const entries = Object.entries(response.data);
        this.setState({ 
          blogPosts: entries.map(p => Object.assign({id: p[0]}, {...p[1]}))
            .sort((p1, p2) => p1.updatedAt > p2.updatedAt ? -1 : 1),
        });
      }
    },
    err => {
      console.log('err=', err);
    });
}

So now the blog posts are populated, but the Pagination component doesn't update (even though the blogs themselves seem to update).

This is where I need some guidance on how React lifecycle hooks work. Does the render method not re-run after the state has changed? I'm expecting the Pagination component to be re-render and this time have the totalRecords prop print out 3 (or some number higher than 0). Does the constructor only run once even if it re-renders?

So just in case I have to trigger a re-render, I ran this in the componentShouldUpdate() method:

shouldComponentUpdate(nextProps, nextState) {
  console.log('this.state.blogPosts.length=', this.state.blogPosts.length);
  console.log('nextState.blogPosts.length=', nextState.blogPosts.length);
  return this.state.blogPosts.length !== nextState.blogPosts.length;
}

Indeed, this.state.blogPosts.length shows 0 and nextState.blogPosts.length shows 3. So they're different, and I'm expecting state to update with 3 blog posts. I return true if the lengths are different, which they are, so the component should update. Does that not mean re-render?

In any case, totalRecords is still 0. I even set a time interval in the Pagination component:

setInterval(() => {
  console.log('this.totalRecords =', this.totalRecords);
}, 5000);

Every five seconds it prints out 0... long after the blog posts have been fetched and added to the state.

Why does the Pagination component not update with the new value for totalRecords?

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
gib65
  • 1,709
  • 3
  • 24
  • 58
  • 1
    It may be more helpful to post a [Minimal, ***Complete***, and Reproducible](https://stackoverflow.com/help/minimal-reproducible-example) component code example. With just a few snippets it is hard to know what else your component may be doing, what your initial state may be, or how your `Pagination` component is handling prop updates. Can you include both the `Pagination` component code ***and*** the component's code that is rendering `Pagination`? What is `this.totalRecords` in the interval? Is it really `this.props.totalRecords`? – Drew Reese Nov 10 '20 at 05:11
  • seems like `this.totalRecords` is probably a typo and should be `this.state.totalRecords`? – andersryanc Nov 10 '20 at 05:13
  • @DrewReese agreed, more information is needed. seems to me like there could be something inside the `` component which is causing it to not re-render itself. – andersryanc Nov 10 '20 at 05:14
  • Sorry for not being detailed enough. Desmond Hiew's answer worked for my situation, so no need to follow up on this. – gib65 Nov 11 '20 at 05:32

1 Answers1

1

Maybe you forgot to use componentWillReceiveProps in Pagination component.

componentWillReceiveProps(nextProps) {
  this.setState({ totalRecords: nextProps.totalRecords })
}
  • That did the trick, Desmond. I guess this means component constructors aren't repeatedly called every time the component is rendered. I put a console.log in the constructor just to be sure, and indeed it is only called once even though totalRecords is now updating thanks to componentWillReceiveProps(). – gib65 Nov 11 '20 at 05:31