I have a lazy loading HOC that wraps a component with a ScrollView. The HOC accepts a data array that is sliced and incrementally passed to the wrapped component when it scrolls to the bottom of the viewport. The HOC also executes a callback function on the original data in its componentDidMount method.
HOC Component
const withLazyLoading = WrappedComponent => {
return class extends React.Component {
static propTypes = {
data: PropTypes.array,
start: PropTypes.number,
limit: PropTypes.number,
bottomOffset: PropTypes.number,
dataKey: PropTypes.string,
onScrollBottom: PropTypes.func,
omMount: PropTypes.func,
};
static defaultProps = {
data: [],
dataKey: 'photos',
start: 0,
limit: 20,
bottomOffset: 20,
onScrollBottom: _.noop,
onMount: _.noop,
};
constructor(props) {
super(props);
this.state = {
offset: _end(props.data, props.start + props.limit),
loaded: props.data.slice(props.start, props.start + props.limit),
total: props.data.length,
loading: false,
};
}
componentDidMount() {
const { data } = this.props;
this.props.onMount(data);
}
...
onScrollBottom(e) {
const {
nativeEvent: { layoutMeasurement, contentOffset, contentSize },
} = e,
{ onScrollBottom: callback, bottomOffset } = this.props;
if (
layoutMeasurement.height + contentOffset.y >=
contentSize.height - bottomOffset
) {
this.load();
if (callback && _.isFunction(callback)) {
e.persist();
callback(e);
}
}
}
...
render() {
const { dataKey, data } = this.props,
{ loaded, loading } = this.state,
childProps = {
..._.omit(this.props, ['data']),
onScrollBottom: this.onScrollBottom.bind(this),
[dataKey]: loaded,
original: data,
};
return (
<>
{loading && this.renderLoadingView()}
<WrappedComponent {...childProps} />
</>
);
}
};
};
export default withLazyLoading;
Wrapped Component
const deviceHeight = Dimensions.get('window').height;
const scrollLimit = deviceHeight ? deviceHeight / 3 : 20;
const prefetchPhotos = data => {
const uris = data.reduce((u, i) => {
if (i.preview_photo) {
u.push(i.preview_photo);
}
return u;
}, []);
CacheManager.prefetch(uris);
};
class ItemsPage extends Component {
...
renderItemsGrid() {
const { items } = this.props,
{ dragging } = this.state;
return (
<Content
scrollEnabled={!dragging}
extraScrollHeight={70}
style={[styles.bottomPadderSm]}
stickyHeaderIndices={[0]}
onMomentumScrollEnd={this.props.onScrollBottom}>
...
<SwipeListView
data={items}
ref={e => (this._swipeListView = e)}
renderItem={this.renderItem}
renderHiddenItem={this.renderHiddenItem}
leftOpenValue={110}
leftActivationValue={110}
swipeToOpenPercent={15}
swipeToClosePercent={25}
previewRowKey={
(items || []).length > 1 ? `${_.first(items || [])?.id || 0}` : null
}
previewOpenValue={40}
previewOpenDelay={1500}
onRowDidOpen={this.onRowDidOpen}
swipeGestureBegan={this.swipeGestureBegan}
swipeGestureEnded={this.swipeGestureEnded}
onLeftActionStatusChange={this.onRowWillOpen}
disableLeftSwipe={true}
closeOnRowPress={true}
closeOnRowOpen={true}
keyExtractor={(item, i) => `${item.id}`}
/>
</Content>
);
}
...
render() {
...
{items.length === 0 ? this.renderEmtpyView() : this.renderItemsGrid()}
...
}
}
export default connect(
state => ({
...
data: state.sales.activeSale ? state.sales.activeSale.items || [] : [],
dataKey: 'items',
limit: 20,
bottomOffset: scrollLimit,
onMount: prefetchPhotos,
}),
{ ... },
)(withLazyLoading(ItemsPage));
I get the following error on an initial navigation to the ItemsPage screen.
Please report: Excessive number of pending callbacks: 501. Some pending callbacks that might have leaked by never being called from native code: {"121":{"module":"NativeAnimatedModule","method":"startAnimatingNode"},"4863":{"module":"UIManager","method":"measure"},"4875":{"module":"NativeAnimatedModule","method":"startAnimatingNode"},"6012":{},
But when I remove componentDidMount method of WithLazyLoading, the error goes away. Any ideas on why I am getting the error or what is causing it? Based on other reports, the error may be promise related, but I am unsure where and how this is occurring.