如何在导航时阻止NavBar菜单重新渲染? React Router v4

时间:2018-01-14 16:09:34

标签: reactjs react-router react-router-v4

我从API服务器获取数据以动态生成NavBar菜单。

问题是每次浏览页面时菜单都会重新渲染。 无法弄清楚它为什么会发生。我尝试使用react-router v4的不同示例,但菜单总是重新渲染。

在动态生成菜单时,您使用什么模式来阻止NavBar菜单重新渲染?

以下是基本设置文件:

Main.js文件:

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文件:

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文件:

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'));

使用React Router v3,此代码可以正常工作:

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

但是在v4中,我无法嵌套路线。

4 个答案:

答案 0 :(得分:2)

即使已经很晚了,我还是想在这里为其他可能为此而苦苦挣扎的人发布答案。

首先,根据@JulesDupont 的回答,您的 <Head /> 组件应该在您的路线之外。

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

export default App;

此外,您正在搜索的模式是使用 <Link> 中的 react-router-dom 标签。如果您可以在这里发布您的 Head 组件,那就太好了。您很有可能在 <a href='/#'> 中使用 <Link to='/#'> 标签而不是 <Menu /> 标签进行重定向。

<a> 标签会触发整个页面重新加载,导致每次导航到新页面时重新安装 <Head /> 组件,从而重新获取所有数据。但是,<Link> 标记不会触发整页重新加载。

示例:

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;

这将确保您的 Head 组件在导航到另一条路线时不会重新渲染或重新获取数据。

答案 1 :(得分:1)

因为您将标题包含为路线,所以每次路线更改时都会重新渲染。只需将标题拉出路线,它就会在基于路径的组件发生变化时保持一致:

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;

答案 2 :(得分:0)

我有一个类似的问题,最终我无法解决它,所以请尝试以下方法。 在我的主要路线更新中,如果没有创建它,则请求菜单。

    #Route.js

    state = {
        menu: null
    };

    componentDidUpdate() {
            if ( !this.state.menu ) {
                this._instanceMenu();
            }
    } 

    render() {
            return (
                    <React.Fragment>
                            { this._renderStaticContent() }
                            <Switch>
                                    <Route exact path={ '/' } component={ DefaultPage } />
                                    <Route component={ Error404 } />
                            </Switch>
                    </React.Fragment>
            );
    };

我第一次通过提取请求它,然后将其存储在localstorage中,之后,如果它已经在localStorage中,则不返回进行提取。

    #Route.js

    _instanceMenu() {
            if ( !this.helper.getMenu() ) {
                    this.helper.instanceMenu( ( menu ) => {
                            this.setState( { menu } );
                    } );
            }

            this.setState( { menu: this.helper.getMenu() } );
    }

可选

    #Helper.js

    instanceMenu = ( callback ) => {
            axios.get(
                    this._urlMenu,
            ).then( ( response ) => {
                    localStorage.setItem( this._menu, JSON.stringify( response.data ) );
                    callback( this.getMenu() );
            } ).catch( ( error ) => {
                    console.log( error );
            } );
    };

    getMenu = () => {
            return JSON.parse( localStorage.getItem( this._menu ) );
    };

最后,我将其与Higer-Order组件(Readme)一起发送到我的组件中

     #Route.js

     _renderStaticContent = () => {
            if ( !this.authService.isLoggedIn() ) return null;

            return <React.Fragment>
                    <Route component={ HeaderContainer } />
                    <Route component={ wrap( SidebarContainer, { 'menu': this.state.menu } ) } />
                    <Route component={ Footer } />
            </React.Fragment>;
    };

PD:对不起,我的英语。

答案 3 :(得分:0)

我也遇到了同样的问题,但这与在路由中包含标题无关。实际上,这种情况不太明显,很难确定。

我们从一个自定义钩子中获取一些信息,但是这个自定义钩子是从状态中返回整个对象,而不是破坏特定字段。因此,对象内部的其他字段(我们不感兴趣)正在根据路线更改进行更新,因此这会触发报头的不必要的重新渲染。

仅提供示例;

我们现在在做什么(不正确)

const { auth } = useSelector(state => state); 

我们将其更改为

const { user } = useSelector(state => state.auth);

auth中的其他字段正在更改,但我们对此不感兴趣。通过仅破坏用户的结构,其他字段将被忽略,并且重新渲染停止。

我意识到这可能是一个非常独特的场景,但希望它可以对某人有所帮助。