Skip to content

Commit

Permalink
perf(react-core): optimize position context calculation (#1813)
Browse files Browse the repository at this point in the history
  • Loading branch information
SergeyAlexeev authored Jan 31, 2019
1 parent 1cc4343 commit b2ea6e7
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 18 deletions.
20 changes: 20 additions & 0 deletions packages/dx-react-core/src/plugin-based/plugin-indexer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,24 @@ describe('PluginIndexer', () => {
.map(wrapper => wrapper.props().position()))
.toEqual([[0, 0], [0, 1], [1]]);
});

it('should memoize position context function', () => {
const Test1 = ({ enableGetter }) => (
<PluginIndexer>
<TestWrapper />
{enableGetter && <TestWrapper />}
</PluginIndexer>
);
Test1.propTypes = {
enableGetter: PropTypes.bool.isRequired,
};

const tree = mount(<Test1 enableGetter={false} />);
const { position } = tree.find(Test).at(0).props();

tree.setProps({ enableGetter: true });

expect(tree.find(Test).at(0).props().position)
.toBe(position);
});
});
57 changes: 39 additions & 18 deletions packages/dx-react-core/src/plugin-based/plugin-indexer.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
import * as React from 'react';
import { PluginPositionFn } from '@devexpress/dx-core';
import { PositionContext } from './contexts';

type MemoizedPluginPositionFn =
(index: number, positionContext: PluginPositionFn) => PluginPositionFn;

type PluginIndexerProps = {
children: React.ReactNode;
};

/** @internal */
export const PluginIndexer = ({ children }) => (
<PositionContext.Consumer>
{positionContext => (
React.Children.map(children, (child, index) => {
if (!child || !child.type) return child;
export class PluginIndexer extends React.PureComponent<PluginIndexerProps> {
indexes: { [index: number]: PluginPositionFn } = {};
memoize: MemoizedPluginPositionFn = (index, positionContext) => {
if (this.indexes[index]) return this.indexes[index];

const fn: PluginPositionFn = () => {
const calculatedPosition = positionContext();
return [...calculatedPosition, index];
};
this.indexes[index] = fn;

const childPosition = () => {
const calculatedPosition = (positionContext && positionContext()) || [];
return [...calculatedPosition, index];
};
return fn;
}
render() {
const { children } = this.props;
return (
<PositionContext.Consumer>
{positionContext => (
React.Children.map(children, (child: any, index: number) => {
if (!child || !child.type) return child;
const childPosition = this.memoize(index, positionContext);

return (
<PositionContext.Provider value={childPosition}>
{child}
</PositionContext.Provider>
);
})
)}
</PositionContext.Consumer>
);
return (
<PositionContext.Provider value={childPosition}>
{child}
</PositionContext.Provider>
);
})
)}
</PositionContext.Consumer>
);
}
}

0 comments on commit b2ea6e7

Please sign in to comment.