'Dynamically populating nested react-native-collapsible

I need to populate a menu with items from an api request. I made some sample items; const items. Some of the menu items have children, and the children can also have children, so I need to nest several levels of menu items.

I made an Accordion() with Collapsible from react-native-collapsible and an AccordionItem() for items that have no children.

function App() renders the menu items twice. Once by manually adding Accordions and AccordionItems and once by mapping items[]. RootMenuItem() is called for each top level item and renders that item and its sub-items by recursion.

When manually adding each item it works the way I want it to. I need to populate the menu programatically, but nested accordions rendered by RootMenuItem() are misbehaving on android and iOS. When testing in Web on snack.io it seems to be working fine.

Here is a snack with my complete App.js: https://snack.expo.dev/@dissar/nested-collapsibles

Am I doing something wrong? Does anybody have any tips for doing this in a better way?

PS: The dynamically rendered items have weird widths when testing on snack.io, but don't worry about that.



Solution 1:[1]

I have a better solution without using any 3rd party library. This is completely customised and easy to understand. I used the same format of data as you used.

first of all, we have a component

const [active, setActive] = useState(null);
return (
<ScrollView
  style={{ marginTop: 50 }}
  contentContainerStyle={styles.container}>
  {arr.map((x, i) => (
    <Item
      key={x.name}
      active={active}
      i={i}
      setActive={setActive}
      child={x.child}
    />
  ))}
</ScrollView>

);

then for the list items and their child

function Item({ i, active, setActive, child }) {
  const onPress = () => {
    LayoutAnimation.easeInEaseOut();
    setActive(i == active ? null : I);
  };
  const [childActive, setChildActive] = useState(null);
  const open = active == I;
  return (
<TouchableOpacity style={styles.item} onPress={onPress} activeOpacity={1}>
  <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
    <Text>Header - {i + 1}</Text>
    {child.length ? <Text>{open ? 'close' : 'open'}</Text> : null}
  </View>
  {open &&
    child.map((x, i) => {
      if (x.child.length) {
        return (
          <Item
            key={x}
            active={childActive}
            i={i}
            setActive={setChildActive}
            child={x.child}
          />
        );
      }
      return (
        <Text key={x} style={styles.subItem}>
          - SOME DATA
        </Text>
      );
    })}
</TouchableOpacity>
);
}

It's a completely dynamic process, you can extend the chain as long as you want. You can also check out the expo to look at its works. https://snack.expo.dev/@akash0208/forlorn-popsicle

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Akash Mishra