Home > Mobile >  How to use createRef to toggle Accordion list items
How to use createRef to toggle Accordion list items

Time:01-17

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>
  )
  }
  }
  

CodePudding user response:

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',
  },
});
  • Related