I have a FlatList and each item is an accordion, I m using class based react and I want to be able to toggle each accordion individually using createRef but I was unsuccessful
export default class shopingScreen extends React.component{
constractor(props){
super(props);
this.state = {
showAccordion : false
}
this.accordian = React.createRef();
}
handleListItem(item,index){
return (
<TouchableOpacity ref={this.accordian} onPress={()=> {this.setState(prevState =>({!prevState.showAccordion}) )
<Icon name='chevron-up'/>
</TouchableOpacity>
{this.state.showAccordion&&<Text>{item}</Text>
}
renderList(){
return (
<View>
<FlatList
data ={fakeList}
keyExtractor ={(item,index)=> Math.random().toString()}
renderItem={({item,index})=> this.handleListItem(item,index)}
</View>
)
}
}
Every thing gets much easier if you take handleListItem
and make it its own component. Each item needs its own accordion, its own boolean state, its own ref, and its own Animation.Value (for the accordion effect). If you tried to manage all that logic in a single component it gets really messy (see AssetExample.js here)
But when separated your list component from the list item component everything is much cleaner link
// List component
import React from 'react';
import { View, FlatList, StyleSheet } from 'react-native';
import { colorGenerator } from '@phantom-factotum/colorutils';
import ListItem from './ListItem';
const fakeList = colorGenerator(5).map((color, i) => ({
color,
title: 'Item ' + (i + 1),
id: 'list-item-' + i,
}));
export default class ShoppingScreen extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<View>
<FlatList
data={fakeList}
keyExtractor={(item, index) => item.id}
renderItem={({ item, index }) => (
<ListItem item={item} index={index} />
)}
/>
</View>
);
}
}
const styles = StyleSheet.create({});
// list item
import React from 'react';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import {
View,
FlatList,
TouchableOpacity,
Text,
Animated,
StyleSheet,
} from 'react-native';
const ITEM_HEIGHT = 50;
export default class ListItem extends React.Component {
constructor(props) {
super(props);
this.state = {
showAccordion: false,
};
this.itemHeight = new Animated.Value(0);
this.itemRef = React.createRef(null);
}
render() {
const showAccordion = this.state.showAccordion;
const animatedStyle = {
height: this.itemHeight.interpolate({
inputRange: [0, 1],
outputRange: [0, ITEM_HEIGHT],
}),
overflow: 'hidden',
};
return (
<TouchableOpacity
style={[
styles.itemContainer,
{ backgroundColor: this.props.item.color },
]}
ref={this.itemRef}
onPress={() => {
const nextVal = !showAccordion;
Animated.timing(this.itemHeight, {
toValue: nextVal ? 1 : 0,
duration: 200,
}).start();
this.setState((prevState) => ({
...prevState,
showAccordion: nextVal,
}));
}}>
<MaterialCommunityIcons
name={showAccordion ? 'chevron-up' : 'chevron-down'}
/>
<Animated.View style={animatedStyle}>
<Text>{this.props.item.title}</Text>
</Animated.View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
itemContainer: {
padding: 5,
paddingVertical: 10,
marginVertical: 10,
// overflow: 'hidden',
},
});