Section list with collapsible section header in react-native

9.1k views Asked by At

I am using react-native version 0.61.5. I want to do a section list with a collapsible header in react-native as shown in the below image.

Here is my API data formate

data:[
  {
    shift_name:'Day',
    data:[
    {
      id:'1',
      fullname: "seela",
      inspection_date: "2020-06-10T04:45:32Z",
      issues: 1,
      response:{
        shift_name:'Day'
      }
     }
    ]
  },
  {
    shift_name:'Afternoon',
    data:[
      {
        id:'2',
        fullname: "Raju vijayan",
        inspection_date: "2020-06-9T04:45:32Z",
        issues: 3,
        response:{
          shift_name:'Afternoon'
        }
      },
      {
        id:'3',
        fullname: "Pratap P",
        inspection_date: "2020-06-8T04:45:32Z",
        issues: 2,
        response:{
          shift_name:'Afternoon'
        }
      }
    ]
  }
]

enter image description here

When I click on header content should expand and collapse. How can I do it in react-native?

2

There are 2 answers

0
Aswin C On BEST ANSWER

Make each item a component.

Use Layoutanimation for your requirement.

Use a state to manage the states of item. ie, open and close.

const [open, setopen] = useState(false);

Initially, the item is in a close state.

Display data according to the condition.

Logic: you only need to specify the height only if the item is closed.

!open && { height: 40 }

if it's not open, give the header height. Otherwise, it will occupy the height it needs.

Full code

import React, { useState } from 'react';
import {
  View, Text, StyleSheet, TouchableOpacity, LayoutAnimation, Platform, UIManager,
} from 'react-native';

if (Platform.OS === 'android') {
  if (UIManager.setLayoutAnimationEnabledExperimental) {
    UIManager.setLayoutAnimationEnabledExperimental(true);
  }
}


export default function TestFile() {
  return (
    <View style={styles.container}>
      <Item />
      <Item />
      <Item />
      <Item />
      <Item />
      <Item />
    </View>
  );
}


function Item() {
  const [open, setopen] = useState(false);
  const onPress = () => {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
    setopen(!open);
  };
  return (
    <TouchableOpacity style={[styles.item, !open && { height: 40 }]} onPress={onPress} activeOpacity={1}>
      <Text>Header</Text>
      {open && (
        <View>
          <Text> SOME DATA</Text>
          <Text> SOME DATA</Text>
          <Text> SOME DATA</Text>
          <Text> SOME DATA</Text>
          <Text> SOME DATA</Text>
          <Text> SOME DATA</Text>
        </View>
      )}
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    padding: 50,
  },
  item: {
    width: '100%',
    borderWidth: 1,
    paddingHorizontal: 20,
    overflow: 'hidden',
    paddingVertical: 10,
    marginBottom: 5,
  },
});

Result

enter image description here

0
Brian H. On

I assume that your data is stored in state, right? So I have an approach which is add an additional property in each of your data named isCollapsed with initial value is true

When a header of an item is clicked, you set isCollapsed of that item to the opposite value.

Then the visibility status of the collapsible view of each item is depend on isCollapse property.

That my solution :) Hope that help :)

Please check my code:

renderItem = (item, index) => {
      return (
          <View>
              // Header content
              <TouchableOpacity
                  onPress={() => {
                      let { data } = this.state;
                      data = data.map((item, key) => {
                          if (key === index) {
                              item.isCollapsed = !item.isCollapsed;
                          }
                          return item;
                      });
                      this.setState({
                          data,
                      });
                  }}
              >
              </TouchableOpacity>

              // Collapsible content
              <View style={{
                  display: (item.isCollapsed) ? 'flex' : 'none'
              }}>

              </View>
          </View>
      );
  }