11

I am working on an application where I need to change the url of the page without causing a re-render.

I am making a call to fetch all the pages inside componentDidMount like this

componentDidMount() {    
    axios.get('/pages')
      .then(response => {
        this.setState({
          pages: response.data,
          slugs: response.data.pages.map(item => Slug(item.title))
        })
      })

Once I have all the pages then I want to show the individual pages. For eg. in the url it has to be like /page/1/slug-for-page-1 and /page/2/slug-for-page-2 based on a state variable activePageNumber and the active page content will be displayed. Also the corresponding slug should be there on the url.

I tried adding a callback after setState like below, but it didn't work.

() => this.props.history.push({
          pathName: '/page',
          state: {activePageNumber : activePageNumber},
        })

I thought of adding a child component to manage the activePageNumber state, but I am not sure if its the best way to do it and whether it'll prevent the re-render.

I can implement it such that each page make a separate request to the backend, but I wish to call it only once, and then update the url based on the active page number.

I am not sure how to implement this in react.

I have the following versions

"react-router-dom": "^5.0.0"

"react": "^16.8.6"

4
  • What's the URL you fetch the pages in before you switch to "/page/1"? Commented May 9, 2019 at 7:40
  • It is '/pages'. Commented May 9, 2019 at 8:14
  • So first you navigate to the "/pages" route and then you navigate to "/page/1" after you fetched the pages? You really should just navigate to "/page/1" and fetch the data from there. Commented May 9, 2019 at 9:44
  • Yes I can do that, but I am planning on making only 1 api call, so I am fetching all the pages and then navigating to different pages using the data. Commented May 9, 2019 at 9:48

2 Answers 2

13

If you define your /page route like this:

<Route
  path="/page/:number"
  component={({ match }) => (
    <Pages activePageNumber={match.params.number} />
  )}
/>

The Pages component method componentDidMount will be called when you switch from, for example, /home to /page/1, but will not be called when you switch from /page/1 to /page/2, because the DOM elements inside the /page/:number Route remain of the same type. I suggest you read React's documentation on reconciliation for a better explaination.

So you can safely put the call to your /pages service inside of the Pages component, and then in its render method display the page you need based on the activePageNumber prop.

class Pages extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      pages: null,
    };
  }

  componentDidMount() {
    axios.get('/pages')
      .then(response => {
        this.setState({
          pages: response.data
        })
      });
  }

  render() {
    const { pages } = this.state;
    const { activePageNumber } = this.props;

    return pages ? (
      <Page page={pages[activePageNumber]} />
    ) : (
      <div>loading...</div>
    );
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the response, but there is another problem, I have a slug for each page which I am computing from the title of each page coming from the axios response, so the url for each page is like /page/1/new-game and also the home page from where I am linking doesn't know about this slug. How should I handle this?
@ShahrukhMohammad you can change the path prop in the Route with /page/:number/:title? to match both /page/1 and /page/1/new-game, refer to this answer. From the front page you can link to /page/1, and when you get your response from the server in the setState callback you can replace that url with /page/1/title-of-the-page.
0

We can make use of Navigate from 'react-router-dom'

const navigate = useNavigate();
<Button onClick={() => navigate('/products/addnewproduct')}>
Click Me
</Button>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.