Reputation: 533
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
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
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