导航时如何防止导航栏菜单重新呈现?反应路由器 v4
How to prevent NavBar Menu to re render when navigating? 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 中我不能嵌套路由。
因为您将 header 作为路线包括在内,每次路线更改时都是 re-rendering。只需将 header 拉出路线,当 route-based 组件发生变化时它将保持一致:
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;
我也遇到过类似的问题,最后还是没能解决,所以试试下面的方法。
在我的主要路线的更新中,请求菜单,如果我没有创建它。
#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>
);
};
第一次fetch请求,然后存到localstorage,后面如果已经在localStorage,我就不return去fetch了。
#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 ) );
};
最后我用高阶组件将它发送到我的组件 (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:对不起我的英语。
我也遇到了同样的问题,但这与路由中的 header 无关。事实上,这是一些不太明显的东西,很难确定。
我们从自定义挂钩中获取一些信息,但是这个自定义挂钩从状态返回整个 object 而不是解构特定字段。因此,object 中的其他字段(我们不感兴趣)在路由更改时更新,因此这触发了 header.[=14= 中不必要的 re-render ]
只是举个例子;
What we WERE doing (incorrect)
const { auth } = useSelector(state => state);
What we changed it to
const { user } = useSelector(state => state.auth);
auth 中的其他字段正在更改,但我们对这些不感兴趣。通过仅对用户进行解构,其他字段将被忽略并且 re-render 停止。
我意识到这可能是一个非常独特的场景,但希望它能对某人有所帮助。
虽然已经晚了,但我想我会 post 在这里为可能正在为此苦苦挣扎的其他人提供答案。
首先,根据@JulesDupont 的回答,您的 <Head />
组件应该在您的路线之外。
const App = () => (
<>
<Head />
<Switch>
<Route exact path='/' component={Component 1}/>
// Add any other routes goes here
</Switch>
</>
)
export default App;
此外,您要搜索的模式是使用 react-router-dom
中的 <Link>
标签。如果您可以在此处 post 您的 Head 组件,那就太好了。您很有可能在 <Menu />
.
中使用 <a href='/#'>
标签而不是 <Link to='/#'>
标签进行重定向
<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 组件在导航到另一条路线时不会重新呈现或重新获取数据。
我正在从 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 中我不能嵌套路由。
因为您将 header 作为路线包括在内,每次路线更改时都是 re-rendering。只需将 header 拉出路线,当 route-based 组件发生变化时它将保持一致:
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;
我也遇到过类似的问题,最后还是没能解决,所以试试下面的方法。 在我的主要路线的更新中,请求菜单,如果我没有创建它。
#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>
);
};
第一次fetch请求,然后存到localstorage,后面如果已经在localStorage,我就不return去fetch了。
#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 ) );
};
最后我用高阶组件将它发送到我的组件 (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:对不起我的英语。
我也遇到了同样的问题,但这与路由中的 header 无关。事实上,这是一些不太明显的东西,很难确定。
我们从自定义挂钩中获取一些信息,但是这个自定义挂钩从状态返回整个 object 而不是解构特定字段。因此,object 中的其他字段(我们不感兴趣)在路由更改时更新,因此这触发了 header.[=14= 中不必要的 re-render ]
只是举个例子;
What we WERE doing (incorrect)
const { auth } = useSelector(state => state);
What we changed it to
const { user } = useSelector(state => state.auth);
auth 中的其他字段正在更改,但我们对这些不感兴趣。通过仅对用户进行解构,其他字段将被忽略并且 re-render 停止。
我意识到这可能是一个非常独特的场景,但希望它能对某人有所帮助。
虽然已经晚了,但我想我会 post 在这里为可能正在为此苦苦挣扎的其他人提供答案。
首先,根据@JulesDupont 的回答,您的 <Head />
组件应该在您的路线之外。
const App = () => (
<>
<Head />
<Switch>
<Route exact path='/' component={Component 1}/>
// Add any other routes goes here
</Switch>
</>
)
export default App;
此外,您要搜索的模式是使用 react-router-dom
中的 <Link>
标签。如果您可以在此处 post 您的 Head 组件,那就太好了。您很有可能在 <Menu />
.
<a href='/#'>
标签而不是 <Link to='/#'>
标签进行重定向
<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 组件在导航到另一条路线时不会重新呈现或重新获取数据。