/ React

PrimeReact menubar with React Router

4youngpadawans.com presents PrimeReact menubar with React Router featuring React | PrimeReact


App's navigation system is very important part of GUI.
Clear and easy approachable navigation system significantly improves user experience. On the other side, developers should always aim to create maintainable navigation system so that new navigation routes can be easily added.
In this story we will create navigation system using PrimeReact Menubar with drop-down menus and React Router.

Basics

Before going to next steps, lets suppose that you've already

In order to achieve our goal, we will need to do following

  • to create several React components that will serve as content containers for app's pages
  • to design navigational component in a form of menubar positioned in the page header,
  • to provide mechanism allowing user to click on menu item and navigate to related page

As a code base we will use Redux enriched project created in article PrimeReact growl with redux but you can omit Redux related stuff pretty easily.

Accessing session's history

There are several ways to make session's history available to React component. The most convenient one is to utilize withRouter and to wrap up component with it prior to exporting. On that way history becomes accessible as one of component's props.

appmenu.jsx

import React, { Component } from 'react';
import {Menubar} from 'primereact/components/menubar/Menubar';
import {connect} from 'react-redux';
import { withRouter } from 'react-router'

import { showGrowl } from '../actions/actions.jsx'
import { showInfoMessage } from '../utils/utils.js';

export class AppMenu extends Component {
	
    navigateToPage = (path) => {
		console.log('Navigate to path ' + path);
		this.props.history.push(path);
        showInfoMessage(this,'Navigation',path);
	}

    render() {
		var items=[
				{label: 'Router navigation', icon: 'fa-compass',
				items: [{label: 'Component 1 route',command:()=>{ this.navigateToPage('/component1')}},
						{label: 'Component 2 route',command:()=>{ this.navigateToPage('/component2')}},
						{label: 'Component 3 route with path param 1',command:()=>{ this.navigateToPage('/component3/1')}},
						{label: 'Component 3 route with path param 2',command:()=>{ this.navigateToPage('/component3/2')}},
						{label: 'Component 4 route with query string',command:()=>{ this.navigateToPage('/component4?name=sith-lord')}}]}
            ];
        return (<Menubar model={items}/>);
    } 
}

const mapDispatchToProps = {  
  showGrowl
};

AppMenu = withRouter(connect(null,mapDispatchToProps)(AppMenu))

export default AppMenu

For more details about how to create Menubar menu items check out all available properties of MenuModel.

Defining navigation routes

We need to make sure that React Router is able to detect programmatic changes of session's history.

index.js

import React from 'react';
import ReactDOM from 'react-dom';

import { Provider } from 'react-redux';
import { createStore } from 'redux'
import appReducers from './reducers/reducers.js'

import { Router, Route } from 'react-router'
import createBrowserHistory from 'history/createBrowserHistory';

import App from './App';
import './index.css';
import { Component1 } from './components/component1.jsx';
import { Component2 } from './components/component2.jsx';
import { Component3 } from './components/component3.jsx';
import { Component4 } from './components/component4.jsx';

let History = createBrowserHistory();
let store = createStore(appReducers);

const render = () =>
  ReactDOM.render(
    <Provider store={store}>
      <Router history={History}>
        <App>
          <Route path="/component1" component={Component1} />
          <Route path="/component2" component={Component2} />
          <Route path="/component3/:id" component={Component3} />
          <Route path="/component4" component={Component4} />
        </App>
      </Router>
    </Provider>,
    document.getElementById('root')
  );

render();

We actually did following:

  • we took session's history by the neck using history library
  • then we passed it to history property of <Router> component.

On that way, Router will be aware of session's history object changes and when any new URL is pushed in history with this.props.history.push(path), React Router will take care that related component/page is mounted and rendered.

Notice that component3 and component4 are defined to receive additional parameters from URL's path and query string respectively.

React components as pages

Let's create components that will serve as containers for pages as well as for functionalities inside each page.

component1.jsx

import React, { Component } from 'react';

export class Component1 extends Component {
    render(){
        return <div><h1>I am component 1</h1></div>;
    }
}

component2.jsx

Just another simple React component...

import React, { Component } from 'react';

export class Component2 extends Component {
    render(){
        return <div><h1>I am component 2</h1></div>;
    }
}

component3.jsx

This component will receive URL path parameter as id property of React Router's match.params object.

import React, { Component } from 'react';

export class Component3 extends Component {
    constructor(props) {
        super(props);
        this.state = { params: null };
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        return { params: nextProps.match.params };
    }

    render() {
        return <div><h1>I am component 3</h1> <h2>with path param {this.state.params.id}</h2></div>;
    }
}

component4.jsx

This component will receive query string parameter as search property of React Router's location object.

import React, { Component } from 'react';
import queryString from 'query-string';

export class Component4 extends Component {
    constructor(props) {
        super(props);
        this.state = { search: null };
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.location.search !== prevState.search) {
            return { search: nextProps.location.search };
        }
        return null;
    }

    render() {
        //following statement parses query string into json object
        const query = queryString.parse(this.state.search);
        return <div><h1>I am component 4</h1> <h2>with query param 'name'={query.name}</h2></div>;
    }
}

Since React 16.3 some life-cycle methods of React component have been deprecated. So instead of deprecated componentWillReceiveProps we are using newly introduced static method getDerivedStateFromProps.

Result

primereact_memubar_router

PrimeReact menubar with React Router
Share this