Skip to content

Commit

Permalink
feat: add list component like flatlist for header, footer and empty
Browse files Browse the repository at this point in the history
  • Loading branch information
marcocesarato committed Jun 6, 2021
1 parent 4f8edfc commit 796c1f7
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 10 deletions.
47 changes: 39 additions & 8 deletions lib/BigList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,8 @@ class BigList extends PureComponent {
}

/**
* BigList only re-renders when items change which which does not happen with
* every scroll event. Since an accessory might depend on scroll position this
* ensures the accessory at least re-renders when scrolling ends
* Handle scroll end.
* @param event
*/
onScrollEnd(event) {
const { renderAccessory, onScrollEnd } = this.props;
Expand Down Expand Up @@ -293,6 +292,11 @@ class BigList extends PureComponent {
*/
renderItems() {
const {
ListEmptyComponent,
ListFooterComponent,
ListFooterComponentStyle,
ListHeaderComponent,
ListHeaderComponentStyle,
renderHeader,
renderFooter,
renderSection,
Expand All @@ -301,8 +305,13 @@ class BigList extends PureComponent {
renderEmpty,
} = this.props;
const { items = [] } = this.state;
if (renderEmpty != null && this.isEmpty()) {
return renderEmpty();
if (this.isEmpty()) {
if (ListEmptyComponent != null) {
return <ListEmptyComponent />;
}
if (renderEmpty != null) {
return renderEmpty();
}
}
const sectionPositions = [];
items.forEach(({ type, position }) => {
Expand All @@ -313,13 +322,24 @@ class BigList extends PureComponent {
const children = [];
items.forEach(({ type, key, position, height, section, row }) => {
let child;
let style;
switch (type) {
case BigListItemType.HEADER:
child = renderHeader();
if (ListFooterComponent != null) {
child = <ListFooterComponent />;
style = ListFooterComponentStyle;
} else {
child = renderHeader();
}
// falls through
case BigListItemType.FOOTER:
if (type === BigListItemType.FOOTER) {
child = renderFooter();
if (ListFooterComponent != null) {
child = <ListHeaderComponent />;
style = ListHeaderComponentStyle;
} else {
child = renderFooter();
}
}
// falls through
case BigListItemType.ROW:
Expand All @@ -340,7 +360,7 @@ class BigList extends PureComponent {
case BigListItemType.ITEM:
if (child != null) {
children.push(
<BigListItem key={key} height={height}>
<BigListItem key={key} height={height} style={style}>
{child}
</BigListItem>,
);
Expand Down Expand Up @@ -498,6 +518,17 @@ BigList.propTypes = {
]),
keyboardDismissMode: PropTypes.string,
keyboardShouldPersistTaps: PropTypes.string,
ListEmptyComponent: PropTypes.element,
ListFooterComponent: PropTypes.element,
ListFooterComponentStyle: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
]),
ListHeaderComponent: PropTypes.element,
ListHeaderComponentStyle: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
]),
onLayout: PropTypes.func,
onScroll: PropTypes.func,
onScrollEnd: PropTypes.func,
Expand Down
6 changes: 4 additions & 2 deletions lib/BigListItem.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PropTypes from "prop-types";
import React, { memo } from "react";
import { View } from "react-native";
import { mergeViewStyle } from "./utils";

export const BigListItemType = {
ITEM: "item",
Expand All @@ -12,8 +13,8 @@ export const BigListItemType = {
SECTION_FOOTER: "section_footer",
};

const BigListItem = ({ height, children }) => (
<View style={{ height }}>{children}</View>
const BigListItem = ({ height, style, children }) => (
<View style={mergeViewStyle(style, { height })}>{children}</View>
);

BigListItem.propTypes = {
Expand All @@ -22,6 +23,7 @@ BigListItem.propTypes = {
PropTypes.node,
]),
height: PropTypes.number,
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

export default memo(BigListItem);
45 changes: 45 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
/**
* Is numeric.
* @param num
* @returns {boolean}
*/
export const isNumeric = (num) => {
return !isNaN(parseFloat(num)) && isFinite(num);
};

/**
* Process block.
* @param containerHeight
* @param scrollTop
* @returns {{blockStart: number, batchSize: number, blockEnd: number}}
*/
export const processBlock = (containerHeight, scrollTop) => {
if (containerHeight === 0) {
return {
Expand All @@ -17,6 +28,12 @@ export const processBlock = (containerHeight, scrollTop) => {
return { batchSize, blockStart, blockEnd };
};

/**
* For each object indexed.
* @param fn
* @param obj
* @returns {*}
*/
export const forEachObjIndexed = (fn, obj) => {
const keyList = Object.keys(obj);
let idx = 0;
Expand All @@ -28,6 +45,11 @@ export const forEachObjIndexed = (fn, obj) => {
return obj;
};

/**
* Autobind context to class methods.
* @param self
* @returns {{}}
*/
export const autobind = (self = {}) => {
const exclude = [
"componentWillMount",
Expand Down Expand Up @@ -80,3 +102,26 @@ export const autobind = (self = {}) => {
}
return self;
};

/**
* Merge styles
* @param style
* @param defaultStyle
* @returns {*[]}
*/
export const mergeViewStyle = (style, defaultStyle) => {
if (style == null) {
style = defaultStyle;
} else if (Array.isArray(style) && Array.isArray(defaultStyle)) {
defaultStyle.concat(style);
style = defaultStyle;
} else if (Array.isArray(defaultStyle)) {
defaultStyle.push(style);
style = defaultStyle;
} else if (Array.isArray(style)) {
style.unshift(defaultStyle);
} else {
style = [defaultStyle, style];
}
return style;
};

0 comments on commit 796c1f7

Please sign in to comment.