biscuitstack
biscuitstack

Reputation: 12102

Cannot get history.push(url) to re-render page

This comes up often, but no solution appears to work and I feel like I've exhausted every option I can think of, so I'm turning to here, believing this may be a slightly different scenario and not a duplicate. If there's an existing solution that works, I'm happy to be shown otherwise.

In my last create-react-app project, I had no problem rendering new pages with Router and useHistory. Using the exact same set up, I've run into the issue where history.push(url) changes the url in the address bar but the page doesn't re-render.

I'm using:

App.js

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { Page } from './stories/Page';
import './App.css';

function App() {


    return (
            <Router>
                <Switch>
                    <Route exact path="/">
                        <Page homepage={true} />
                    </Route>
                    <Route path="/project/([a-zA-Z0-9]+)/([a-z\-0-9]+)/([a-z\-0-9]+)/" render={urlprops =>
                        <Page projectID={urlprops.match.params[0]} homepage={false} />
                    } />
                    <Route path="/project/([a-zA-Z0-9]+)/([a-z\-0-9]+)/" render={urlprops =>
                        <Page projectID={urlprops.match.params[0]} homepage={false} />
                    } />
                </Switch>
            </Router>
        
    );

}

export default App;

component-page.js

import React, { useEffect, useState, useCallback } from 'react';
import PropTypes from 'prop-types';
import { useHistory } from 'react-router-dom'; 
import './menuitem.css';

export const Component = ({ url, ...props }) => {

    let history = useHistory();

    function handleItemClick(e) {
        history.push(url); // <- calls fine, tested with logging to console
    }
    ...

I've seen older solutions suggest passing history props through Router but in my last app I was able to use the set up above, and any level nested subcomponent would be able to call the useHistory hook and use push if they were set up like component-page.js above. Therefore I haven't shown the components between App.js and component-page.js on the belief that this should be irrelevant to useHistory functioning correctly.

Possibly relevant:


Update

Checking history in console after calling history.push('url string') shows the following under the location property. This looks like it's acting as intended (I'm only expecting pathname to match the url I tried to point to).

{
    "pathname": "url string",
    "search": "",
    "hash": "",
    "key": "ctks7v"
}

Update 2

Possible progress. In my Page component I am calling fetch in a hook to catch any update, like so:

useEffect(() => {
    apiFetchProject(projectID);
}, []);

I'm now wondering if this is my problem? That this hook isn't seeing the url as a change that requires firing apiFetchProject(projectID). The reason I say this is that console calls confirm this hook isn't being called here after my history.push, but a console call to the Page component is happening. I've tried calling the hook with any change in props.location but this comes back as undefined each time, which means the hook isn't called.

Update 3

If, on Page, I use import { useLocation } from "react-router-dom"; with let location = useLocation(); and let a hook look for a change in location, Page now successfully calls fetch after a history.push call. But something doesn't seem right about having to do this too? I feel I would have seen it as a standard instruction.

I'm having to add it to every component to see re-rendering of anything. The fetch in Page is stored as a state and passed down as a prop to subcomponents. A change of this state should automatically re-render all subcomponents that are passed it, as happens when the page is loaded.

Upvotes: 4

Views: 1033

Answers (1)

Aakash Rathee
Aakash Rathee

Reputation: 593

instead of the url, put the path ('/home')

Upvotes: 1

Related Questions