Search code examples
javascriptreactjsreact-routerurl-routing

React Router - Change state of other components


When using React Router, how can I change the state of another component when the page is being routed?

For example, I have an app structured like this:

Header
==Link1 Link2==
Footer: "You are now at Home", button1, button2

When the user is routed to Link1, I would like to update the state of the footer so that it knows that it is currently on link1. For example, the footer is a toolbar, and some buttons will be disabled on Link1, but all buttons will be available on both Link2 and Home. Like this:

==Header==
==Link1 Link2==
==Content of Link1==
Footer: "You are now at Link1", button2

The solution I can think of is to wrap both the footer and content of the links into a big, single component, and set up routes to that whole component. But I'm not sure if this is a good practice, since I guess it kind of defeats the purpose of a "footer".

Another thought is that maybe I can change the state of the footer component when routing is in action, so the footer will re-render when it's necessary. The <Footer /> component thus sits outside of the main contents, on the same level like the <Header />. However, I have no idea how to do this.

Is there a better way to achieve this?

Here is the code snippet on CodeSandbox, I hope it could illustrate my problem better.

CodeSandbox demo


Solution

  • One way to go would be to use the withRouter HOC on the Footer so that it receives the props when the route is changed.

    Changes to code

    import { BrowserRouter, Route, Link, withRouter } from "react-router-dom";
    

    then

    <BrowserRouter>
      <div>
        <Route path="/" exact component={Home} />
        <Route path="/section1" component={SectionOne} />
        <WrappedFooter />
      </div>
    </BrowserRouter>
    

    and then

    const WrappedFooter = withRouter(Footer);
    

    You can now use the this.props.location.pathname inside the footer to access the currently matched route from the router. You should use the actual path in your switch let text, {location} = this.props

    switch (location.pathname) {
      case '/': {
        text = 'Home'
        break
      }
      case '/section1': {
        text = 'Section One'
        break
      }
    }
    

    https://codesandbox.io/s/8y051k9qoj