Skip to content

Support delayed stabilisation for simple list #167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions examples/index.es6
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ const examples = [
length: 10000,
itemRenderer: renderVariableHeightItem
},
{
length: 10000,
itemRenderer: renderVariableHeightItem,
className: 'is-animated',
stableFrameDelay: 500
},
{
axis: 'x',
length: 10000,
Expand Down Expand Up @@ -126,9 +132,13 @@ const examples = [
export default class extends React.Component {
renderExamples() {
return examples.map((props, key) =>
<div key={key} className={`example axis-${props.axis}`}>
<div key={key}
className={`example axis-${props.axis} ${props.className}`}
>
<strong>Props</strong>
<pre className='props'>{JSON.stringify(props, null, 2)}</pre>
<pre className='props'>{
JSON.stringify(props, null, 2).replace(/\\n\s+/g, ' ')
}</pre>
<strong>Component</strong>
<div className='component'><ReactList {...props} /></div>
</div>
Expand Down
11 changes: 9 additions & 2 deletions examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@
var examples = [{
length: 10000,
itemRenderer: renderVariableHeightItem
}, {
length: 10000,
itemRenderer: renderVariableHeightItem,
className: 'is-animated',
stableFrameDelay: 500
}, {
axis: 'x',
length: 10000,
Expand Down Expand Up @@ -230,7 +235,9 @@
return examples.map(function (props, key) {
return _react2.default.createElement(
'div',
{ key: key, className: 'example axis-' + props.axis },
{ key: key,
className: 'example axis-' + props.axis + ' ' + props.className
},
_react2.default.createElement(
'strong',
null,
Expand All @@ -239,7 +246,7 @@
_react2.default.createElement(
'pre',
{ className: 'props' },
JSON.stringify(props, null, 2)
JSON.stringify(props, null, 2).replace(/\\n\s+/g, ' ')
),
_react2.default.createElement(
'strong',
Expand Down
11 changes: 11 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@
.even {
background: linear-gradient(#ddd, #ccc);
}

@keyframes grow {
0% { max-height: 0; }
100% { max-height: 120px; }
}

.is-animated .item {
line-height: 120px;
overflow: hidden;
animation: grow 0.5s ease 0s;
}
</style>
</head>

Expand Down
13 changes: 12 additions & 1 deletion react-list.es6
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ module.exports = class ReactList extends Component {
minSize: PropTypes.number,
pageSize: PropTypes.number,
scrollParentGetter: PropTypes.func,
stableFrameDelay: PropTypes.number,
threshold: PropTypes.number,
type: PropTypes.oneOf(['simple', 'variable', 'uniform']),
useStaticSize: PropTypes.bool,
Expand Down Expand Up @@ -90,6 +91,7 @@ module.exports = class ReactList extends Component {

componentWillReceiveProps(next) {
let {from, size, itemsPerRow} = this.state;
clearTimeout(this.updateFrameTimeoutId);
this.maybeSetState(this.constrain(from, size, itemsPerRow, next), NOOP);
}

Expand All @@ -100,6 +102,7 @@ module.exports = class ReactList extends Component {
}

componentDidUpdate() {
let {stableFrameDelay, type} = this.props;

// If the list has reached an unstable state, prevent an infinite loop.
if (this.unstable) return;
Expand All @@ -116,7 +119,14 @@ module.exports = class ReactList extends Component {
}, 0);
}

this.updateFrame();
if (type === 'simple' && stableFrameDelay) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to restrict this prop to the 'simple' list type. It seems like it could potentially be used for 'variable' or 'uniform' as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, based on my interpretation of the documentation, on variable you have to provide the height, so animating your elements should not interfere with it.
About uniform, I've tried to enable it on but it didn't work out of the box. So, if you think it might be useful I might give it a second try (but I might need to touch more code).

this.updateFrameTimeoutId = setTimeout(
this.updateFrame, stableFrameDelay
);
} else {
this.updateFrame();
}

}

maybeSetState(b, cb) {
Expand All @@ -129,6 +139,7 @@ module.exports = class ReactList extends Component {
window.removeEventListener('resize', this.updateFrame);
this.scrollParent.removeEventListener('scroll', this.updateFrame, PASSIVE);
this.scrollParent.removeEventListener('mousewheel', NOOP, PASSIVE);
clearTimeout(this.updateFrameTimeoutId);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's check if this.updateFrameTimeoutId exists first. I believe some JS interpreters throw when trying to clearTimeout on undefined.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking the timeout is superfluous (see MDN note).

}

getOffset(el) {
Expand Down
70 changes: 41 additions & 29 deletions react-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
size = _state.size,
itemsPerRow = _state.itemsPerRow;

clearTimeout(this.updateFrameTimeoutId);
this.maybeSetState(this.constrain(from, size, itemsPerRow, next), NOOP);
}
}, {
Expand All @@ -164,6 +165,11 @@
value: function componentDidUpdate() {
var _this2 = this;

var _props = this.props,
stableFrameDelay = _props.stableFrameDelay,
type = _props.type;


// If the list has reached an unstable state, prevent an infinite loop.
if (this.unstable) return;

Expand All @@ -179,7 +185,11 @@
}, 0);
}

this.updateFrame();
if (type === 'simple' && stableFrameDelay) {
this.updateFrameTimeoutId = setTimeout(this.updateFrame, stableFrameDelay);
} else {
this.updateFrame();
}
}
}, {
key: 'maybeSetState',
Expand All @@ -194,6 +204,7 @@
window.removeEventListener('resize', this.updateFrame);
this.scrollParent.removeEventListener('scroll', this.updateFrame, PASSIVE);
this.scrollParent.removeEventListener('mousewheel', NOOP, PASSIVE);
clearTimeout(this.updateFrameTimeoutId);
}
}, {
key: 'getOffset',
Expand All @@ -210,9 +221,9 @@
}, {
key: 'getScrollParent',
value: function getScrollParent() {
var _props = this.props,
axis = _props.axis,
scrollParentGetter = _props.scrollParentGetter;
var _props2 = this.props,
axis = _props2.axis,
scrollParentGetter = _props2.scrollParentGetter;

if (scrollParentGetter) return scrollParentGetter();
var el = findDOMNode(this);
Expand Down Expand Up @@ -276,9 +287,9 @@
}, {
key: 'hasDeterminateSize',
value: function hasDeterminateSize() {
var _props2 = this.props,
itemSizeGetter = _props2.itemSizeGetter,
type = _props2.type;
var _props3 = this.props,
itemSizeGetter = _props3.itemSizeGetter,
type = _props3.type;

return type === 'uniform' || itemSizeGetter;
}
Expand All @@ -298,9 +309,9 @@
}, {
key: 'getItemSizeAndItemsPerRow',
value: function getItemSizeAndItemsPerRow() {
var _props3 = this.props,
axis = _props3.axis,
useStaticSize = _props3.useStaticSize;
var _props4 = this.props,
axis = _props4.axis,
useStaticSize = _props4.useStaticSize;
var _state2 = this.state,
itemSize = _state2.itemSize,
itemsPerRow = _state2.itemsPerRow;
Expand Down Expand Up @@ -377,9 +388,9 @@

if (elEnd > end) return cb();

var _props4 = this.props,
pageSize = _props4.pageSize,
length = _props4.length;
var _props5 = this.props,
pageSize = _props5.pageSize,
length = _props5.length;

var size = Math.min(this.state.size + pageSize, length);
this.maybeSetState({ size: size }, cb);
Expand All @@ -393,9 +404,9 @@
start = _getStartAndEnd2.start,
end = _getStartAndEnd2.end;

var _props5 = this.props,
length = _props5.length,
pageSize = _props5.pageSize;
var _props6 = this.props,
length = _props6.length,
pageSize = _props6.pageSize;

var space = 0;
var from = 0;
Expand Down Expand Up @@ -490,11 +501,11 @@
value: function getSizeOf(index) {
var cache = this.cache,
items = this.items;
var _props6 = this.props,
axis = _props6.axis,
itemSizeGetter = _props6.itemSizeGetter,
itemSizeEstimator = _props6.itemSizeEstimator,
type = _props6.type;
var _props7 = this.props,
axis = _props7.axis,
itemSizeGetter = _props7.itemSizeGetter,
itemSizeEstimator = _props7.itemSizeEstimator,
type = _props7.type;
var _state4 = this.state,
from = _state4.from,
itemSize = _state4.itemSize,
Expand Down Expand Up @@ -582,9 +593,9 @@
value: function renderItems() {
var _this3 = this;

var _props7 = this.props,
itemRenderer = _props7.itemRenderer,
itemsRenderer = _props7.itemsRenderer;
var _props8 = this.props,
itemRenderer = _props8.itemRenderer,
itemsRenderer = _props8.itemsRenderer;
var _state6 = this.state,
from = _state6.from,
size = _state6.size;
Expand All @@ -599,11 +610,11 @@
}, {
key: 'render',
value: function render() {
var _props8 = this.props,
axis = _props8.axis,
length = _props8.length,
type = _props8.type,
useTranslate3d = _props8.useTranslate3d;
var _props9 = this.props,
axis = _props9.axis,
length = _props9.length,
type = _props9.type,
useTranslate3d = _props9.useTranslate3d;
var _state7 = this.state,
from = _state7.from,
itemsPerRow = _state7.itemsPerRow;
Expand Down Expand Up @@ -653,6 +664,7 @@
minSize: _propTypes2.default.number,
pageSize: _propTypes2.default.number,
scrollParentGetter: _propTypes2.default.func,
stableFrameDelay: _propTypes2.default.number,
threshold: _propTypes2.default.number,
type: _propTypes2.default.oneOf(['simple', 'variable', 'uniform']),
useStaticSize: _propTypes2.default.bool,
Expand Down