I'm learning React and using React-router. The app I'm building is a mobile style app with a top navigation menu, and a content section below. As I navigate the app pages I'd like to add a page 'title' to the menu bar to identify which page you are currently on.
My routes:
<Routes>
<Route name='home' path='/' handler={HomePage}>
<Route name='product-list' path='products/' handler={ProductList}/>
<Route name='product-detail' path='product/:slug/' handler={ProductDetail} addHandlerKey={true}/>
</Route>
</Routes>
HomePage.render:
<div className="container">
<NavigationMenu />
<div className="contents">
{this.props.activeRouteHandler()}
</div>
</div>
NavigationMenu.render:
<div className="navigationMenu">
<div className="navigationMenuTitle>{this.props.title}</div>
</div>
The child routes to HomePage need to set their title based on content returned from an Ajax call.
I had thought to add callbacks to each route, passing title back to their parent class which could in turn pass this data to the NavigationMenu. Unfortunately this does not work: As you navigate through the pages, the only function that is repeatedly called is render and setting state here raises an Invariant Violation
error.
Use the useLocation() hook to get the current route with React Router, e.g. const location = useLocation() . The hook returns the current location object. For example, you can access the pathname as location.
Write the dynamic component for the title. You can write an independent component for this example, like this: // TitleComponent. jsx import React from 'react'; import Helmet from 'react-helmet'; const TitleComponent = ({ title }) => { var defaultTitle = '⚛️ app'; return ( <Helmet> <title>{title ?
The basename prop is used to provide a base URL path for all the locations in the application. For example, if you want to render your application at the /admin path instead of rendering at the root path / , then specify the basename prop in <BrowserRouter> : <BrowserRouter basename="/admin"> <App /></BrowerRouter>
I was able to solve this using the React Flux pattern and re-organising my app layout.
Title component:
var Title = React.createClass({
getInitialState: function() {
return {
title: Store.get()
};
},
componentDidMount: function () {
Store.addChangeListener(this._onChange);
},
componentWillUnmount: function() {
Store.removeChangeListener(this._onChange);
},
_onChange: function() {
this.setState({
title: Store.get()
});
},
render: function() {
return (
<span className="Title">{this.state.title}</span>
);
}
});
Page / content components follow this structure:
var Image = React.createClass({
componentDidMount: function() {
Action.update('Image - '+ this.props.params.service);
},
render: function() {
var src = "http://place"+this.props.params.service+".com/g/400/400";
return (
<div className="Image">
<img src={src}/>
</div>
);
}
});
This allows components to load, setting a title dynamically and update only the title component when the app is good and ready! Nifty!
As Jeff Fairley suggested above, using Reflux will help clean this up quite a bit (this code uses ES6 featues, so a transpiler will be needed to run it):
TitleActions
import Reflux from 'reflux';
export default Reflux.createActions([ 'update' ]);
TitleStore
import Reflux from 'reflux';
import TitleActions from '../actions/title';
export default Reflux.createStore({
listenables: TitleActions,
getInitialState: function() {
return 'My Cool New Project';
},
onUpdate(title) {
this.trigger(title);
}
});
NavigationMenu
import React from 'react/addons';
import Reflux from 'reflux';
import TitleStore from '../stores/title';
export default React.createClass({
mixins: [ Reflux.connect(TitleStore, 'title') ],
render() {
return <div className="navigationMenu">
<div className="navigationMenuTitle>{this.state.title}</div>
</div>;
}
});
MyComponent
import React from 'react/addons';
import Reflux from 'reflux';
import TitleActions from '../actions/title';
export default React.createClass({
componentDidMount() {
TitleActions.update('My Custom Title');
},
render() {
return <div>My content.</div>;
}
});
The goal is to preserve a smooth uni-directional data flow:
MyComponent -> update action -> TitleStore -> NavigationMenu
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With