diff --git a/Accordion.d.ts b/Accordion.d.ts index ebee458..59ce5a7 100644 --- a/Accordion.d.ts +++ b/Accordion.d.ts @@ -53,6 +53,13 @@ export interface AccordionProps { */ onChange(indexes: number[]): void; + /** + * Used to extract a unique key for a given item at the specified index. Key is used for caching + * and as the react key to track item re-ordering. The default extractor checks `item.key`, then + * falls back to using the index, like React does. + */ + keyExtractor?: (item: T, index: number) => number | string; + /** * Controls whether user can interact with accordion */ @@ -73,9 +80,10 @@ export interface AccordionProps { expandMultiple?: boolean; /** - * Control which indices in the sections array are currently open. If empty, closes all sections. + * Control which indices from keyEctractor in the sections array are currently + * open. If empty, closes all sections. */ - activeSections: number[]; + activeSections: number[] | string[]; /** * The color of the underlay that will show through when tapping on headers. @@ -126,6 +134,13 @@ export interface AccordionProps { * Optional styling for the Accordion container */ containerStyle?: StyleProp; + + /** + * Render the Accordion as a FlatList. Defaults to false for legacy behavior. + * + * @default false + */ + renderAsFlatList?: boolean; } export default class Accordion extends React.Component> {} diff --git a/Accordion.js b/Accordion.js index 30119e3..ccf0b9b 100644 --- a/Accordion.js +++ b/Accordion.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { View, TouchableHighlight } from 'react-native'; +import { View, TouchableHighlight, FlatList } from 'react-native'; import Collapsible from './Collapsible'; const COLLAPSIBLE_PROPS = [ @@ -20,9 +20,11 @@ export default class Accordion extends Component { expandFromBottom: false, expandMultiple: false, touchableComponent: TouchableHighlight, + keyExtractor: (item, index) => index, renderSectionTitle: () => null, onAnimationEnd: () => null, sectionContainerStyle: {}, + renderAsFlatList: false, }; _toggleSection(section) { @@ -45,6 +47,44 @@ export default class Accordion extends Component { } } + _renderContainer = (section, key, renderCollapsible) => { + const { + activeSections, + sectionContainerStyle, + expandFromBottom, + sections, + underlayColor, + touchableProps, + touchableComponent: Touchable, + renderHeader, + renderFooter, + renderSectionTitle, + } = this.props; + return ( + + {renderSectionTitle(section, key, activeSections.includes(key))} + + {expandFromBottom && renderCollapsible(section, key)} + + this._toggleSection(key)} + underlayColor={underlayColor} + {...touchableProps} + accessibilityState={{ + expanded: activeSections.includes(key), + }} + > + {renderHeader(section, key, activeSections.includes(key), sections)} + + + {!expandFromBottom && renderCollapsible(section, key)} + + {renderFooter && + renderFooter(section, key, activeSections.includes(key), sections)} + + ); + }; + render() { const { activeSections, @@ -63,6 +103,8 @@ export default class Accordion extends Component { renderFooter, renderSectionTitle, disabled, + renderAsFlatList, + keyExtractor, ...restProps } = this.props; @@ -87,41 +129,30 @@ export default class Accordion extends Component { ); + if (renderAsFlatList) { + return ( + { + const section = item; + const key = keyExtractor(item, index); + return this._renderContainer(section, key, renderCollapsible); + }} + {...viewProps} + /> + ); + } + return ( - {sections.map((section, key) => ( - - {renderSectionTitle(section, key, activeSections.includes(key))} - - {expandFromBottom && renderCollapsible(section, key)} - - this._toggleSection(key)} - underlayColor={underlayColor} - {...touchableProps} - accessibilityState={{ - expanded: activeSections.includes(key), - }} - > - {renderHeader( - section, - key, - activeSections.includes(key), - sections - )} - - - {!expandFromBottom && renderCollapsible(section, key)} - - {renderFooter && - renderFooter( - section, - key, - activeSections.includes(key), - sections - )} - - ))} + {sections.map((section, index) => { + const key = keyExtractor(section, index); + return this._renderContainer(section, key, renderCollapsible); + })} ); } diff --git a/Example/App.js b/Example/App.js index 53d61f0..5554fa9 100644 --- a/Example/App.js +++ b/Example/App.js @@ -155,6 +155,7 @@ export default class App extends Component { renderContent={this.renderContent} duration={400} onChange={this.setSections} + renderAsFlatList={false} /> diff --git a/README.md b/README.md index 70c1cfd..c8e6e9f 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ import Accordion from 'react-native-collapsible/Accordion'; | **`renderFooter(content, index, isActive, sections)`** | A function that should return a renderable representing the footer | | **`renderSectionTitle(content, index, isActive)`** | A function that should return a renderable representing the title of the section outside the touchable element | | **`onChange(indexes)`** | A function that is called when the currently active section(s) are updated. | +| **`keyExtractor(item, index)`** | Used to extract a unique key for a given item at the specified index. | | **`activeSections`** | Control which indices in the `sections` array are currently open. If empty, closes all sections. | | **`underlayColor`** | The color of the underlay that will show through when tapping on headers. Defaults to black. | | **`touchableComponent`** | The touchable component used in the Accordion. Defaults to `TouchableHighlight` | @@ -77,6 +78,7 @@ import Accordion from 'react-native-collapsible/Accordion'; | **`expandMultiple`** | Allow more than one section to be expanded. Defaults to false. | | **`sectionContainerStyle`** | Optional styling for the section container. | | **`containerStyle`** | Optional styling for the Accordion container. | +| **`renderAsFlatList`** | Optional rendering as FlatList (defaults to false). | ## Demo