Pio
Pio

Reputation: 533

React Change Navbar title based on rendered page

I have this BrowserRouter component as my top level component with a title string in its state. This component renders a NavigationComponent which is basically a nav bar, in there i would like to set a title which changes depending on where i go on the site.

The component looks roughly like this

  changeTitle(title) {
    this.setState({
      title: title,
    })
  }

  <BrowserRouter>
    <div>
      <NavigationComponent title={this.state.title}/>
      <Switch>
        <Route exact path="/" render={(props) => (
          <App {...props} changeTitle= {this.changeTitle.bind(this)}/>
        )} />
        <Route exact path="/login" component={LoginComponent }/>
        <Route exact path="/logout" component={LoginComponent }/>
      </Switch>
    </div>
  </BrowserRouter>

Now i know how to expose the method changeTitle to the App Component. But i'd like to expose the method further and the way i've implemented it atm is this:

class App extends React.Component{
  constructor(props){
    super(props);
  }

  changeTitle(title) {
    this.props.changeTitle(title);
  }

  render(){
    return(
      <OverviewComponent changeTitle= {this.changeTitle.bind(this)}/>
  }
} // note: App component stripped down

In the Overviewcomponent is the first time i actually call the changeTitle function.

My Question is now: is there a more clever way to implement this without piping the method changeTitle to every child? There are many more components which are called after the OverviewComponent and those need to change the title too.

Upvotes: 1

Views: 6396

Answers (2)

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15708

In your NavigationComponent, I think it would make more sense to have an event-listener that would check for whenever you navigated to another page. It looks like you're already using react-router-dom, so this is perfect.

You need to wrap your component with the withRouter HOC from react-router-dom. This will give us access to the history prop, which has an event listener method. We can create that event-listener in componentDidMount() so its always active.

import { withRouter } from "react-router-dom"

class NavigationComponent extends React.Component{
   state = {
      title: "Home"
   }

   changeTitle = (newTitle) => {
      this.setState({
          title: newTitle
      })
   }

   componentDidMount(){
    //listens for any route changes
    this.props.history.listen(() => {
        this.changeTitle(window.location.pathname) <-- this can be whatever value you want.
    })
   }

   render(){
      <div>{this.state.title}</div>
   }
}

export default withRouter(NavigationComponent)

This seems to be alot more intuitive than having to pass in values from another component.

Upvotes: 5

Engineer
Engineer

Reputation: 1261

Check window.location.pathname and make pathname as Navbar title

// Navbar.js
changeTitle = () => {
  switch(window.location.pathname){
    case '/profile':
      return 'Profile';
    case '/admin':
      return 'Admin';
    default:
      return 'Dashboard';
  }
}
render(){
 let title = changeTitle();
  return(<div>{title}</div>)
} 

Upvotes: 1

Related Questions