Skip to content
Snippets Groups Projects
Commit 0bc6de13 authored by Paul Kaplan's avatar Paul Kaplan
Browse files

Throttle updates to assets on sprite selector item via HOC

Adds unit tests for this HOC.
parent 0910b2ec
No related branches found
No related tags found
No related merge requests found
......@@ -8,9 +8,12 @@ import Box from '../box/box.jsx';
import SpriteSelectorItem from '../../containers/sprite-selector-item.jsx';
import SortableHOC from '../../lib/sortable-hoc.jsx';
import SortableAsset from '../asset-panel/sortable-asset.jsx';
import ThrottledPropertyHOC from '../../lib/throttled-property-hoc.jsx';
import styles from './sprite-selector.css';
const ThrottledSpriteSelectorItem = ThrottledPropertyHOC('asset', 500, SpriteSelectorItem);
const SpriteList = function (props) {
const {
containerRef,
......@@ -74,7 +77,7 @@ const SpriteList = function (props) {
onAddSortable={onAddSortable}
onRemoveSortable={onRemoveSortable}
>
<SpriteSelectorItem
<ThrottledSpriteSelectorItem
asset={sprite.costume && sprite.costume.asset}
className={classNames(styles.sprite, {
[styles.raised]: isRaised,
......
import React from 'react';
/* Higher Order Component to throttle updates to specific props.
* Why? Because certain prop updates are expensive, and need to be throttled.
* This allows renders when other properties change, and will use the last
* rendered value of a prop for comparison.
* @param {string} propName the name of the prop to throttle updates from.
* @param {string} throttleTime the minimum time between updates to that specific property.
* @param {React.Component} WrappedComponent component who will not update for certain props.
* @returns {React.Component} component with throttling behavior
*/
const ThrottledPropertyHOC = function (propName, throttleTime, WrappedComponent) {
class ThrottledPropertyWrapper extends React.Component {
shouldComponentUpdate (nextProps) {
for (const property in nextProps) {
if (property !== propName && this.props[property] !== nextProps[property]) {
return true; // Always update if another property has changed
}
}
// If only that prop has changed, allow update to go to render based
// on _lastRenderedTime and _lastRenderTime are updated in render
if (nextProps[propName] !== this._lastRenderedValue &&
Date.now() - this._lastRenderTime > throttleTime
) {
return true; // Allow this update to go to render
}
return false;
}
render () {
this._lastRenderTime = Date.now();
this._lastRenderedValue = this.props[propName];
return (
<WrappedComponent {...this.props} />
);
}
}
return ThrottledPropertyWrapper;
};
export default ThrottledPropertyHOC;
import React from 'react';
import {mount} from 'enzyme';
import ThrottledPropertyHOC from '../../../src/lib/throttled-property-hoc.jsx';
describe('VMListenerHOC', () => {
let mounted;
const throttleTime = 500;
beforeEach(() => {
const Component = ({propToThrottle, doNotThrottle}) => (
<input
name={doNotThrottle}
value={propToThrottle}
/>
);
const WrappedComponent = ThrottledPropertyHOC('propToThrottle', throttleTime, Component);
global.Date.now = () => 0;
mounted = mount(
<WrappedComponent
doNotThrottle="oldvalue"
propToThrottle={0}
/>
);
});
test('it passes the props on initial render ', () => {
expect(mounted.find('[value=0]').exists()).toEqual(true);
expect(mounted.find('[name="oldvalue"]').exists()).toEqual(true);
});
test('it does not rerender if throttled prop is updated too soon', () => {
global.Date.now = () => throttleTime / 2;
mounted.setProps({propToThrottle: 1});
mounted.update();
expect(mounted.find('[value=0]').exists()).toEqual(true);
});
test('it does rerender if throttled prop is updated after throttle timeout', () => {
global.Date.now = () => throttleTime * 2;
mounted.setProps({propToThrottle: 1});
mounted.update();
expect(mounted.find('[value=1]').exists()).toEqual(true);
});
test('it does rerender if a non-throttled prop is changed', () => {
global.Date.now = () => throttleTime / 2;
mounted.setProps({doNotThrottle: 'newvalue', propToThrottle: 2});
mounted.update();
expect(mounted.find('[name="newvalue"]').exists()).toEqual(true);
expect(mounted.find('[value=2]').exists()).toEqual(true);
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment