Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent NavBar Menu to re render when navigating? React Router v4

I'm fetching data from an API server to generate the NavBar Menu dynamically.

Problem is that the menu re-renders each time I navigate through the pages. Can't figure out why it's happening. I tried different examples for react-router v4 like using but the menu is always re-rendering.

What pattern do you use to prevent NavBar Menu from re-rendering when generating the Menu dynamically?

Here are the basic setup files:

Main.js file:

import React from 'react'
import { Route } from 'react-router-dom'
import Home2 from './Home'
import Head from './Head'
import Rules from './Rules'

const Main = () => (
  <main>
    <Route  path='/' component={Head}/>
    <Route exact path='/' component={Home}/>
    <Route exact path='/rules' component={Rules}/>
  </main>
)

export default Main

Head.js file:

import React, { Component } from 'react'
import Menu from 'semantic-ui-react'

class Head extends Component {
  constructor(props) {
   super(props);
  }

  getInitialData() {
    //fetch data from server
  }

  componentWillMount() {
    this.getInitialData();
  }

  render() {
    return (
      <header>
        <nav>
          <Menu>
            {/* fetched data */}
        </nav>
      </header>
    )
  }
}

export default Head

Index.js file:

import React from 'react'
import { render } from 'react-dom'
import Main from './components/Main'
import { BrowserRouter } from 'react-router-dom'

render((
  <BrowserRouter>
    <Main />
  </BrowserRouter>
), document.getElementById('root'));

Using React Router v3 this code works fine:

var Routes = (
  <Router>
    <Route path="/" component={Head}>
      <IndexRoute component={Home} />
    </Route>
  </Router>
);

But in v4 I can't nest Routes.

like image 331
Stramike Avatar asked Jan 14 '18 16:01

Stramike


People also ask

How do you prevent re renders react?

But, is there an option to prevent re-rendering with functional components? The answer is yes! Use React. memo() to prevent re-rendering on React function components.

How do I restrict navigation in react JS?

To restrict access to routes in React Router, we set the render prop to a function that renders the component we want according to the condition we're checking. import { Route, Redirect } from "react-router"; <Route exact path="/" render={() => (loggedIn ?

How do you handle routing and navigation in react JS?

React Router overview add links for navigation. define the route of each page, meaning the URL path and the component that we want to load. define a router which will check if the requested URL is defined in the routes, and if it is, return the component.


2 Answers

Even though it is late, I thought I'd post the answer here for other people who might be struggling with this.

First of all, as per the answer by @JulesDupont, your <Head /> component should be outside of your routes.

const App = () => (
  <>
    <Head />
    <Switch>
      <Route exact path='/' component={Component 1}/>
      // Add any other routes goes here
    </Switch>
  </>
)

export default App;

Additionally, the pattern that you are searching for is the use of the <Link> tags from react-router-dom. It would be great if you could post your Head component here. There is a strong chance that you are using <a href='/#'> tags to redirect instead of <Link to='/#'> tags inside of your <Menu />.

<a> tags would trigger an entire page reload, causing your <Head /> component to get re mounted each time you navigate to a new page, hence re-fetching all the data. However, the <Link> tag does not not trigger full page reloads.

Example:

import { Link } from 'react-router-dom';

const Head = () => {
    return (
        <ul>
            <Link to='/your-route'>Item 1 (fetches data)<Link>
            <Link to='/your-other-route'>Item 2 (fetches data)</Link>
        </ul>
    )
}

export default Head;

This will ensure that your Head component does not re-render or re-fetches data when navigating to another route.

like image 150
Zeeshaan Maudarbocus Avatar answered Sep 29 '22 22:09

Zeeshaan Maudarbocus


Because you're including the header as a route, it's re-rendering every time the route changes. Just pull the header out of the route and it will stay consistent while the route-based components change:

import React from 'react'
import { Route, Switch } from 'react-router-dom'
import Home2 from './Home'
import Head from './Head'

const Main = () => (
  <main>
    <Head />
    <Switch>
      <Route exact path='/' component={Home}/>
      // Add any other routes you want here
    </Switch>
  </main>
)

export default Main;
like image 28
Jules Dupont Avatar answered Sep 30 '22 00:09

Jules Dupont