Skip to content

Commit

Permalink
Profiled and optimized the example app
Browse files Browse the repository at this point in the history
  • Loading branch information
riccardo-forina committed Oct 11, 2019
1 parent 2cc70c9 commit 5ecb8f2
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 127 deletions.
153 changes: 80 additions & 73 deletions example/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,90 +3,97 @@ import '@patternfly/react-core/dist/styles/base.css';
import { Brand } from '@patternfly/react-core';
import * as React from 'react';
import { Redirect, useHistory } from 'react-router-dom';
import { LastLocationProvider } from 'react-router-last-location';
import { AppLayout, LazyRoute, SwitchWith404 } from 'use-patternfly';
import './app.css';
import logo from './use-patternfly.png';

const Logo = <Brand src={logo} alt={'use-patternfly logo'} />;
const navItems = [
{
title: 'Overview',
to: '/',
exact: true
},
{
title: 'Getting Started',
to: '/getting-started',
items: [
{ to: '/getting-started/installation', title: 'Installation' },
{ to: '/getting-started/usage', title: 'Usage' },
]
},
{
title: 'API',
to: '/api',
items: [
{ to: '/api/AppLayout', title: 'AppLayout' },
{ to: '/api/AppNavExpandable', title: 'AppNavExpandable' },
{ to: '/api/AppNavGroup', title: 'AppNavGroup' },
{ to: '/api/AppNavItem', title: 'AppNavItem' },
{ to: '/api/LazyRoute', title: 'LazyRoute' },
{ to: '/api/Loading', title: 'Loading' },
{ to: '/api/NotFound', title: 'NotFound' },
{ to: '/api/SwitchWith404', title: 'SwitchWith404' },
{ to: '/api/useA11yRoute', title: 'useA11yRoute' },
{ to: '/api/useBreadcrumb', title: 'useBreadcrumb' },
{ to: '/api/useDocumentTitle', title: 'useDocumentTitle' },
],
}, {
title: 'Examples',
to: '/examples',
items: [
{ to: '/examples/async-data-list', title: 'Async Data List' },
],
},
];

const getOverviewPage = () => import('./pages/OverviewPage');
const getInstallationPage = () => import('./pages/InstallationPage');
const getUsagePage = () => import('./pages/UsagePage');
const getAsyncDataList = () => import('./pages/AsyncDataList');

export const App = () => {
const history = useHistory();
const logoProps = React.useMemo(() => ({
onClick: () => history.push('/')
}), [history]);
return (
<AppLayout
logo={<Brand src={logo} alt={'use-patternfly logo'} />}
logoProps={{
onClick: () => history.push('/')
}}
logo={Logo}
logoProps={logoProps}
navVariant={'vertical'}
navItems={[
{
title: 'Overview',
to: '/',
exact: true
},
{
title: 'Getting Started',
to: '/getting-started',
items: [
{ to: '/getting-started/installation', title: 'Installation' },
{ to: '/getting-started/usage', title: 'Usage' },
]
},
{
title: 'API',
to: '/api',
items: [
{ to: '/api/AppLayout', title: 'AppLayout' },
{ to: '/api/AppNavExpandable', title: 'AppNavExpandable' },
{ to: '/api/AppNavGroup', title: 'AppNavGroup' },
{ to: '/api/AppNavItem', title: 'AppNavItem' },
{ to: '/api/LazyRoute', title: 'LazyRoute' },
{ to: '/api/Loading', title: 'Loading' },
{ to: '/api/NotFound', title: 'NotFound' },
{ to: '/api/SwitchWith404', title: 'SwitchWith404' },
{ to: '/api/useA11yRoute', title: 'useA11yRoute' },
{ to: '/api/useBreadcrumb', title: 'useBreadcrumb' },
{ to: '/api/useDocumentTitle', title: 'useDocumentTitle' },
],
}, {
title: 'Examples',
to: '/examples',
items: [
{ to: '/examples/async-data-list', title: 'Async Data List' },
],
},
]}
navItems={navItems}
navGroupsStyle={'expandable'}
>
<LastLocationProvider>
<SwitchWith404>
<LazyRoute
path='/'
exact={true}
getComponent={() => import('./pages/OverviewPage')}
/>
<Redirect
path={'/getting-started'}
to={'/getting-started/installation'}
exact={true}
/>
<LazyRoute
path='/getting-started/installation'
getComponent={() => import('./pages/InstallationPage')}
/>
<LazyRoute
path='/getting-started/usage'
getComponent={() => import('./pages/UsagePage')}
/>
<Redirect
path='/api'
to={'/api/AppLayout'}
exact={true}
/>
<LazyRoute
path='/examples/async-data-list/:page?'
getComponent={() => import('./pages/AsyncDataList')}
/>
</SwitchWith404>
<SwitchWith404>
<LazyRoute
path='/'
exact={true}
getComponent={getOverviewPage}
/>
<Redirect
path={'/getting-started'}
to={'/getting-started/installation'}
exact={true}
/>
<LazyRoute
path='/getting-started/installation'
getComponent={getInstallationPage}
/>
<LazyRoute
path='/getting-started/usage'
getComponent={getUsagePage}
/>
<Redirect
path='/api'
to={'/api/AppLayout'}
exact={true}
/>
<LazyRoute
path='/examples/async-data-list/:page?'
getComponent={getAsyncDataList}
/>
</SwitchWith404>
</AppLayout>
);
};
127 changes: 75 additions & 52 deletions src/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const AppLayout: React.FunctionComponent<IAppLayoutProps> = ({
React.ReactNode | undefined
>();
const previousBreadcrumb = React.useRef<React.ReactNode | null>();

const handleSetBreadcrumb = React.useCallback(
(newBreadcrumb: React.ReactNode) => {
if (previousBreadcrumb.current !== newBreadcrumb) {
Expand All @@ -63,12 +64,14 @@ export const AppLayout: React.FunctionComponent<IAppLayoutProps> = ({
[setBreadcrumb, previousBreadcrumb]
);

const onNavToggleMobile = () => {
const onNavToggleMobile = React.useCallback(() => {
setIsNavOpenMobile(!isNavOpenMobile);
};
const onNavToggle = () => {
}, [setIsNavOpenMobile, isNavOpenMobile]);

const onNavToggle = React.useCallback(() => {
setIsNavOpen(!isNavOpen);
};
}, [setIsNavOpen, isNavOpen]);

const onPageResize = (props: { mobileView: boolean; windowSize: number }) => {
setIsMobileView(props.mobileView);
};
Expand All @@ -80,57 +83,73 @@ export const AppLayout: React.FunctionComponent<IAppLayoutProps> = ({
const isVertical = navVariant === 'vertical';
const variant = isVertical ? NavVariants.default : NavVariants.horizontal;

const Navigation =
navItems.length > 0 ? (
<Nav id="nav-primary-simple" theme={theme}>
<NavList id="nav-list-simple" variant={variant}>
{navItems.map((navItem, idx) => {
if (navItem && navItem.hasOwnProperty('items') && isVertical) {
return navGroupsStyle === 'expandable' ? (
<AppNavExpandable
{...(navItem as IAppNavExpandableProps)}
key={idx}
/>
) : (
<AppNavGroup {...(navItem as IAppNavGroupProps)} key={idx} />
);
} else {
return (
<AppNavItem {...(navItem as IAppNavItemProps)} key={idx} />
);
}
})}
</NavList>
</Nav>
) : null;

const Header = (
<PageHeader
logo={logo}
logoProps={logoProps}
avatar={avatar}
toolbar={toolbar}
showNavToggle={isVertical}
isNavOpen={isVertical ? isNavOpen : undefined}
onNavToggle={isMobileView ? onNavToggleMobile : onNavToggle}
topNav={isVertical ? undefined : Navigation}
/>
const Navigation = React.useMemo(
() =>
navItems.length > 0 ? (
<Nav id="nav-primary-simple" theme={theme}>
<NavList id="nav-list-simple" variant={variant}>
{navItems.map((navItem, idx) => {
if (navItem && navItem.hasOwnProperty('items') && isVertical) {
return navGroupsStyle === 'expandable' ? (
<AppNavExpandable
{...(navItem as IAppNavExpandableProps)}
key={idx}
/>
) : (
<AppNavGroup {...(navItem as IAppNavGroupProps)} key={idx} />
);
} else {
return (
<AppNavItem {...(navItem as IAppNavItemProps)} key={idx} />
);
}
})}
</NavList>
</Nav>
) : null,
[isVertical, navGroupsStyle, navItems, theme, variant]
);

const Sidebar =
navVariant === 'vertical' ? (
<PageSidebar
nav={Navigation}
isNavOpen={isMobileView ? isNavOpenMobile : isNavOpen}
theme={theme}
data-testid="app-sidebar"
const Header = React.useMemo(
() => (
<PageHeader
logo={logo}
logoProps={logoProps}
avatar={avatar}
toolbar={toolbar}
showNavToggle={isVertical}
isNavOpen={isVertical ? isNavOpen : undefined}
onNavToggle={isMobileView ? onNavToggleMobile : onNavToggle}
topNav={isVertical ? undefined : Navigation}
/>
) : (
undefined
);
),
[
logo,
logoProps,
avatar,
toolbar,
isVertical,
isNavOpen,
isMobileView,
onNavToggle,
onNavToggleMobile,
Navigation,
]
);

const PageSkipToContent = (
<SkipToContent href="#primary-app-container">Skip to Content</SkipToContent>
const Sidebar = React.useMemo(
() =>
navVariant === 'vertical' ? (
<PageSidebar
nav={Navigation}
isNavOpen={isMobileView ? isNavOpenMobile : isNavOpen}
theme={theme}
data-testid="app-sidebar"
/>
) : (
undefined
),
[navVariant, Navigation, isMobileView, isNavOpenMobile, isNavOpen, theme]
);

return (
Expand All @@ -141,7 +160,11 @@ export const AppLayout: React.FunctionComponent<IAppLayoutProps> = ({
sidebar={Sidebar}
breadcrumb={breadcrumb}
onPageResize={onPageResize}
skipToContent={PageSkipToContent}
skipToContent={
<SkipToContent href="#primary-app-container">
Skip to Content
</SkipToContent>
}
>
{children}
</Page>
Expand Down
4 changes: 3 additions & 1 deletion src/LazyRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ export interface IDynamicImportProps extends RouteProps {
}

export function LazyRoute({ getComponent, ...props }: IDynamicImportProps) {
const LazyComponent = React.lazy(getComponent);
const LazyComponent = React.useMemo(() => React.lazy(getComponent), [
getComponent,
]);
return (
<Route {...props}>
<React.Suspense fallback={<Loading />}>
Expand Down
6 changes: 5 additions & 1 deletion src/SwitchWith404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ export const SwitchWith404: React.FunctionComponent<SwitchProps> = ({
...props
}) => {
const match = useRouteMatch();
const defaultMatch = React.useMemo(
() => match && <Route path={match.path} exact={true} />,
[match]
);
return (
<Switch {...props}>
{children}
{/*
* Default route that matches the parent route, to avoid showing a 404
* for "junction" pages . See the "Dashboard" example.
*/}
{match && <Route path={match.path} exact={true} />}
{defaultMatch}
<Route>
<NotFound />
</Route>
Expand Down

0 comments on commit 5ecb8f2

Please sign in to comment.