import React, { Component } from 'react'; import { View, Dimensions, ViewPropTypes, SectionList, } from 'react-native'; import PropTypes from 'prop-types'; import { generateStyles, calculateDimensions, chunkArray } from './utils'; class SectionGrid extends Component { constructor(props) { super(props); this.onLayout = this.onLayout.bind(this); this.renderRow = this.renderRow.bind(this); const { staticDimension } = props; // Calculate total dimensions and set to state let totalDimension = staticDimension; if (!staticDimension) { totalDimension = Dimensions.get('window').width; } this.state = { totalDimension, }; } onLayout(e) { const { staticDimension, onLayout } = this.props; const { totalDimension } = this.state; if (!staticDimension) { const { width: newTotalDimension } = e.nativeEvent.layout || {}; if (totalDimension !== newTotalDimension) { this.setState({ totalDimension: newTotalDimension, }); } } // call onLayout prop if passed if (onLayout) { onLayout(e); } } renderRow({ rowItems, rowIndex, section, itemsPerRow, rowStyle, separators, isFirstRow, containerStyle, }) { const { spacing, itemContainerStyle, renderItem } = this.props; // Add spacing below section header let additionalRowStyle = {}; if (isFirstRow) { additionalRowStyle = { marginTop: spacing, }; } return ( {rowItems.map((item, i) => ( {renderItem({ item, index: (rowIndex * itemsPerRow) + i, section, separators, rowIndex, })} ))} ); } render() { const { sections, style, spacing, fixed, itemDimension, staticDimension, renderItem, onLayout, ...restProps } = this.props; const { totalDimension } = this.state; const { containerDimension, itemsPerRow, fixedSpacing } = calculateDimensions({ itemDimension, staticDimension, totalDimension, spacing, fixed, }); const { containerStyle, rowStyle } = generateStyles({ itemDimension, containerDimension, spacing, fixedSpacing, fixed, }); const groupedSections = sections.map((section) => { const chunkedData = chunkArray(section.data, itemsPerRow); return { ...section, data: chunkedData, originalData: section.data, }; }); return ( this.renderRow({ rowItems: item, rowIndex: index, section, isFirstRow: index === 0, itemsPerRow, rowStyle, containerStyle, })} keyExtractor={(_, index) => `row_${index}`} style={style} onLayout={this.onLayout} ref={(sectionList) => { this.sectionList = sectionList; }} {...restProps} /> ); } } SectionGrid.propTypes = { renderItem: PropTypes.func.isRequired, sections: PropTypes.arrayOf(PropTypes.any).isRequired, itemDimension: PropTypes.number, fixed: PropTypes.bool, spacing: PropTypes.number, style: ViewPropTypes.style, itemContainerStyle: ViewPropTypes.style, staticDimension: PropTypes.number, onLayout: PropTypes.func, }; SectionGrid.defaultProps = { fixed: false, itemDimension: 120, spacing: 10, style: {}, itemContainerStyle: undefined, staticDimension: undefined, onLayout: null, }; export default SectionGrid;