Switched tabs to render to avoid unnecessary mount cycles (#28389) (#28419)

* Switched tabs to render to avoid unnecessary mount cycles

We were previously using the 'component' prop for React Router routes inside of our history tabs component, which causes lots of extra mount cycles. Using the 'render' prop avoids that.

We also decided to *only* allow the render prop, which means using a component is a little more verbose b/c you have to pass down props from the render method, but it's worth it to avoid accidentally using 'component'.

For more, see: https://reacttraining.com/react-router/web/api/Route

Specifically:

"When you use component (instead of render or children, below) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop (below)."

* Prevents trace list from flickering on data load, while still preventing inaccurate no items message while loading

* Updates tests
This commit is contained in:
Jason Rhodes 2019-01-09 21:55:27 -05:00 committed by GitHub
parent 9a4f5e353e
commit 475b271a12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 19 additions and 18 deletions

View file

@ -20,12 +20,12 @@ const homeTabs: IHistoryTab[] = [
{
path: '/services',
name: 'Services',
component: ServiceOverview
render: props => <ServiceOverview {...props} />
},
{
path: '/traces',
name: 'Traces',
component: TraceOverview
render: props => <TraceOverview {...props} />
}
];

View file

@ -39,14 +39,14 @@ exports[`Home component should render 1`] = `
tabs={
Array [
Object {
"component": [Function],
"name": "Services",
"path": "/services",
"render": [Function],
},
Object {
"component": [Function],
"name": "Traces",
"path": "/traces",
"render": [Function],
},
]
}

View file

@ -26,7 +26,7 @@ export class ServiceDetailTabs extends React.Component<TabsProps> {
name: 'Transactions',
path: `/${serviceName}/transactions/${transactionTypes[0]}`,
routePath: `/${serviceName}/transactions/:transactionType?`,
component: () => (
render: () => (
<TransactionOverview
urlParams={urlParams}
serviceTransactionTypes={transactionTypes}
@ -36,7 +36,7 @@ export class ServiceDetailTabs extends React.Component<TabsProps> {
{
name: 'Errors',
path: `/${serviceName}/errors`,
component: () => {
render: () => {
return (
<ErrorGroupOverview urlParams={urlParams} location={location} />
);
@ -45,7 +45,7 @@ export class ServiceDetailTabs extends React.Component<TabsProps> {
{
name: 'Metrics',
path: `/${serviceName}/metrics`,
component: () => <ServiceMetrics urlParams={urlParams} />
render: () => <ServiceMetrics urlParams={urlParams} />
}
];

View file

@ -70,12 +70,13 @@ const traceListColumns: ITableColumn[] = [
];
export function TraceList({ items = [], noItemsMessage, isLoading }: Props) {
return isLoading ? null : (
const noItems = isLoading ? null : noItemsMessage;
return (
<ManagedTable
columns={traceListColumns}
items={items}
initialSort={{ field: 'impact', direction: 'desc' }}
noItemsMessage={noItemsMessage}
noItemsMessage={noItems}
initialPageSize={25}
/>
);

View file

@ -40,17 +40,17 @@ describe('HistoryTabs', () => {
{
name: 'One',
path: '/one',
component: () => <Content name="one" />
render: props => <Content {...props} name="one" />
},
{
name: 'Two',
path: '/two',
component: () => <Content name="two" />
render: () => <Content name="two" />
},
{
name: 'Three',
path: '/three',
component: () => <Content name="three" />
render: () => <Content name="three" />
}
];

View file

@ -55,19 +55,19 @@ exports[`HistoryTabs should render correctly 1`] = `
size="l"
/>
<Route
component={[Function]}
key="/one"
path="/one"
render={[Function]}
/>
<Route
component={[Function]}
key="/two"
path="/two"
render={[Function]}
/>
<Route
component={[Function]}
key="/three"
path="/three"
render={[Function]}
/>
</React.Fragment>
`;

View file

@ -17,7 +17,7 @@ export interface IHistoryTab {
path: string;
routePath?: string;
name: React.ReactNode;
component?: React.SFC | React.ComponentClass;
render?: (props: RouteComponentProps) => React.ReactNode;
}
export interface HistoryTabsProps extends RouteComponentProps {
@ -51,10 +51,10 @@ const HistoryTabsWithoutRouter = ({
</EuiTabs>
<EuiSpacer />
{tabs.map(tab =>
tab.component ? (
tab.render ? (
<Route
path={tab.routePath || tab.path}
component={tab.component}
render={tab.render}
key={tab.path}
/>
) : null