Improve performance while rendering the navbar

Only re-render the navbar if needed
This commit is contained in:
Grégoire Delattre 2017-05-21 17:24:10 +02:00
parent 5cdae9f334
commit 908f930081
2 changed files with 99 additions and 56 deletions

View File

@ -50,7 +50,11 @@ import TorrentList from './components/torrents/list'
function Main(props) {
return (
<div>
<NavBar {...props}/>
<NavBar
username={props.userStore.username}
router={props.router}
torrentCount={props.torrentStore.torrents.length}
/>
<Alert {...props}/>
<div className="container-fluid">
{React.cloneElement(props.children, props)}

View File

@ -2,41 +2,100 @@ import React from 'react'
import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'
import { LinkContainer } from 'react-router-bootstrap'
export default function NavBar(props) {
return (
<div>
<Navbar fluid fixedTop collapseOnSelect>
<Navbar.Header>
<LinkContainer to="/">
<Navbar.Brand><a href="#">Canapé</a></Navbar.Brand>
</LinkContainer>
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
<MoviesDropdown username={props.userStore.username} />
<ShowsDropdown username={props.userStore.username} />
<WishlistDropdown username={props.userStore.username} />
<Torrents
username={props.userStore.username}
torrentsCount={props.torrentStore.torrents.length}
/>
<UserDropdown username={props.userStore.username} />
<Search
placeholder="Search movies"
router={props.router}
path='/movies/search'
pathMatch='movies'
/>
<Search
placeholder="Search shows"
router={props.router}
path='/shows/search'
pathMatch='shows'
/>
</Navbar.Collapse>
</Navbar>
</div>
);
export default class NavBar extends React.Component {
constructor(props) {
super(props);
this.state = {
userLoggedIn: (props.username !== ""),
displayMoviesSearch: this.shouldDisplayMoviesSearch(props.router),
displayShowsSearch: this.shouldDisplayShowsSearch(props.router),
};
}
shouldComponentUpdate(nextProps, nextState) {
if (nextProps.username !== this.props.username) {
return true;
}
if (nextProps.torrentsCount !== this.props.torrentsCount) {
return true;
}
if (nextState.displayMoviesSearch !== this.state.displayMoviesSearch) {
return true;
}
if (nextState.displayShowsSearch !== this.state.displayShowsSearch) {
return true;
}
if (nextState.userLoggedIn !== this.state.userLoggedIn) {
return true;
}
return false;
}
componentWillReceiveProps(nextProps) {
// Update the state based on the next props
const shouldDisplayMoviesSearch = this.shouldDisplayMoviesSearch(nextProps.router);
const shouldDisplayShowsSearch = this.shouldDisplayShowsSearch(nextProps.router);
if ((this.state.displayMoviesSearch !== shouldDisplayMoviesSearch)
|| (this.state.displayShowsSearch !== shouldDisplayShowsSearch)) {
this.setState({
userLoggedIn: (nextProps.username !== ""),
displayMoviesSearch: shouldDisplayMoviesSearch,
displayShowsSearch: shouldDisplayShowsSearch,
});
}
}
shouldDisplayMoviesSearch(router) {
return this.matchPath(router, 'movies');
}
shouldDisplayShowsSearch(router) {
return this.matchPath(router, 'shows');
}
matchPath(router, keyword) {
const location = router.getCurrentLocation().pathname;
return (location.indexOf(keyword) !== -1)
}
render() {
return (
<div>
<Navbar fluid fixedTop collapseOnSelect>
<Navbar.Header>
<LinkContainer to="/">
<Navbar.Brand><a href="#">Canapé</a></Navbar.Brand>
</LinkContainer>
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
{this.state.userLoggedIn &&
<MoviesDropdown />
}
{this.state.userLoggedIn &&
<ShowsDropdown />
}
{this.state.userLoggedIn &&
<WishlistDropdown />
}
{this.state.userLoggedIn &&
<Torrents torrentsCount={this.props.torrentCount} />
}
<UserDropdown username={this.props.username} />
{(this.state.displayMoviesSearch && this.state.userLoggedIn) &&
<Search
placeholder="Search movies"
router={this.props.router}
path='/movies/search'
/>
}
{(this.state.displayShowsSearch && this.state.userLoggedIn) &&
<Search
placeholder="Search shows"
router={this.props.router}
path='/shows/search'
/>
}
</Navbar.Collapse>
</Navbar>
</div>
);
}
}
class Search extends React.Component {
@ -48,15 +107,7 @@ class Search extends React.Component {
ev.preventDefault();
this.props.router.push(`${this.props.path}/${encodeURI(this.input.value)}`);
}
isActive() {
const location = this.props.router.getCurrentLocation().pathname;
return (location.indexOf(this.props.pathMatch) !== -1)
}
render() {
if (!this.isActive()) {
return null;
}
return(
<div className="navbar-form navbar-right">
<form className="input-group" onSubmit={(ev) => this.handleSearch(ev)}>
@ -72,9 +123,6 @@ class Search extends React.Component {
}
function MoviesDropdown(props) {
if (props.username === "") {
return null;
}
return(
<Nav>
<NavDropdown title="Movies" id="navbar-movies-dropdown">
@ -90,9 +138,6 @@ function MoviesDropdown(props) {
}
function ShowsDropdown(props) {
if (props.username === "") {
return null;
}
return(
<Nav>
<NavDropdown title="Shows" id="navbar-shows-dropdown">
@ -136,9 +181,6 @@ function UserDropdown(props) {
}
function WishlistDropdown(props) {
if (props.username === "") {
return null;
}
return(
<Nav>
<NavDropdown title="Wishlist" id="navbar-wishlit-dropdown">
@ -154,9 +196,6 @@ function WishlistDropdown(props) {
}
function Torrents(props) {
if (props.username === "") {
return null;
}
return(
<Nav>
<LinkContainer to="/torrents">