简体   繁体   中英

Why do I need to refresh the page when using Link and Switch with react-router-dom?

I am a beginner with React and I am trying to show a new page of my website. I have been using Switch and Link from react-router-dom. When I click on a link, the path is modified correctly but it stays on the same page until I refresh it. Once refreshed, the right page is shown. Does anyone know why it needs to be refreshed and if there is a solution? If not, is there a way to refresh the page automatically?

Here is my code for the Home component:

  render() {
    return (
      <div className="Page">
        <Router>
          <Link to="/MyFiles" className="Element">
            My files
          </Link>
        </Router>
      </div>
    );
  }
}

Here is my code in the Route settings:

        <Switch>
          <Route
            exact
            path="/"
            component={() => (
              <ConnectedHome
                user={this.state.connectedUser}
                logout={this.logout}
              />
            )}
          />
          <Route
            path="/MyFiles"
            component={() => (
              <MyFiles user={this.state.connectedUser} logout={this.logout} />
            )}
          />
        </Switch>
      );

I also get these errors in the console

Warning: Cannot update during an existing state transition (such as within render ). Render methods should be a pure function of props and state.

and

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

I don't know if they are related to this problem.

Thank you in advance for your help !

No need of using router again in Home component. Router should be present at top level where all your routes are defined

  render() {
    return (
      <div className="Page">
          <Link to="/MyFiles" className="Element">
            My files
          </Link>
      </div>
    );
  }
}

When route changes from a child component it reaches to its nearest router in the parent-child tree hierarchy. If any route is defined for the changed route in this router than the component renders or else same page is shown.

So in your case when the route changes to "/MyFiles" it doesn't reaches the top level router where you have defined the Route for "/MyFiles" and hence the page remains the same and not re-renders. Only when you manually refresh it re-renders.

Using inline function in

<Route component={() => <SomeComponent/>}/>

is not good practise. Instead you should replace that with

<Route render={(props) => <SomeComponent {...props} yourProperty1={something} yourProperty2={something} />}/>

Because your component will be unmounted everytime when updates. When you will do this, the warrning disapears and it should work.

Here is article in documentation about it

https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Route.md#component

When you use component (instead of render or children, below) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop (below).

You will be also able to access property history which is injected by router to the <SomeComponent/> and use that for redirection on click if you need

const SomeComponent = ({ history }) => {
    return <Button onClick={() => history.push('yourSubRoute')} />
}

The next problem what I see is that you are using router for wrapping <Link/> . Router should be used only once for example in App.js like this

export const = () = App {
    <Router>
       <Switch>
          <Route path='path1'>
          <Route path='path2>
       </Switch>
    </Router>
}

In <SomeCompnent/> just use <Link/> without wrapping it to <Router/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM