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) { function Main(props) {
return ( return (
<div> <div>
<NavBar {...props}/> <NavBar
username={props.userStore.username}
router={props.router}
torrentCount={props.torrentStore.torrents.length}
/>
<Alert {...props}/> <Alert {...props}/>
<div className="container-fluid"> <div className="container-fluid">
{React.cloneElement(props.children, props)} {React.cloneElement(props.children, props)}

View File

@ -2,7 +2,58 @@ import React from 'react'
import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap' import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'
import { LinkContainer } from 'react-router-bootstrap' import { LinkContainer } from 'react-router-bootstrap'
export default function NavBar(props) { 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 ( return (
<div> <div>
<Navbar fluid fixedTop collapseOnSelect> <Navbar fluid fixedTop collapseOnSelect>
@ -13,30 +64,38 @@ export default function NavBar(props) {
<Navbar.Toggle /> <Navbar.Toggle />
</Navbar.Header> </Navbar.Header>
<Navbar.Collapse> <Navbar.Collapse>
<MoviesDropdown username={props.userStore.username} /> {this.state.userLoggedIn &&
<ShowsDropdown username={props.userStore.username} /> <MoviesDropdown />
<WishlistDropdown username={props.userStore.username} /> }
<Torrents {this.state.userLoggedIn &&
username={props.userStore.username} <ShowsDropdown />
torrentsCount={props.torrentStore.torrents.length} }
/> {this.state.userLoggedIn &&
<UserDropdown username={props.userStore.username} /> <WishlistDropdown />
}
{this.state.userLoggedIn &&
<Torrents torrentsCount={this.props.torrentCount} />
}
<UserDropdown username={this.props.username} />
{(this.state.displayMoviesSearch && this.state.userLoggedIn) &&
<Search <Search
placeholder="Search movies" placeholder="Search movies"
router={props.router} router={this.props.router}
path='/movies/search' path='/movies/search'
pathMatch='movies'
/> />
}
{(this.state.displayShowsSearch && this.state.userLoggedIn) &&
<Search <Search
placeholder="Search shows" placeholder="Search shows"
router={props.router} router={this.props.router}
path='/shows/search' path='/shows/search'
pathMatch='shows'
/> />
}
</Navbar.Collapse> </Navbar.Collapse>
</Navbar> </Navbar>
</div> </div>
); );
}
} }
class Search extends React.Component { class Search extends React.Component {
@ -48,15 +107,7 @@ class Search extends React.Component {
ev.preventDefault(); ev.preventDefault();
this.props.router.push(`${this.props.path}/${encodeURI(this.input.value)}`); 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() { render() {
if (!this.isActive()) {
return null;
}
return( return(
<div className="navbar-form navbar-right"> <div className="navbar-form navbar-right">
<form className="input-group" onSubmit={(ev) => this.handleSearch(ev)}> <form className="input-group" onSubmit={(ev) => this.handleSearch(ev)}>
@ -72,9 +123,6 @@ class Search extends React.Component {
} }
function MoviesDropdown(props) { function MoviesDropdown(props) {
if (props.username === "") {
return null;
}
return( return(
<Nav> <Nav>
<NavDropdown title="Movies" id="navbar-movies-dropdown"> <NavDropdown title="Movies" id="navbar-movies-dropdown">
@ -90,9 +138,6 @@ function MoviesDropdown(props) {
} }
function ShowsDropdown(props) { function ShowsDropdown(props) {
if (props.username === "") {
return null;
}
return( return(
<Nav> <Nav>
<NavDropdown title="Shows" id="navbar-shows-dropdown"> <NavDropdown title="Shows" id="navbar-shows-dropdown">
@ -136,9 +181,6 @@ function UserDropdown(props) {
} }
function WishlistDropdown(props) { function WishlistDropdown(props) {
if (props.username === "") {
return null;
}
return( return(
<Nav> <Nav>
<NavDropdown title="Wishlist" id="navbar-wishlit-dropdown"> <NavDropdown title="Wishlist" id="navbar-wishlit-dropdown">
@ -154,9 +196,6 @@ function WishlistDropdown(props) {
} }
function Torrents(props) { function Torrents(props) {
if (props.username === "") {
return null;
}
return( return(
<Nav> <Nav>
<LinkContainer to="/torrents"> <LinkContainer to="/torrents">