skip to Main Content

I have a SectionList divided into 3 sections:

  1. General User Info
  2. User Vehicle Info
  3. Other Options

The General Info Items need to be TouchableOpacity components so that when a user clicks on them, they route to an update page to update this data.

The Vehicle Info Items are just Text components, but I do need an "Add Vehicle" Button component at the end of this section at all times no matter how many vehicles have been added.

The Other Options Section can all be TouchableOpacity components that redirect to a different page within the application.

How can I render different components within different sections of my SectionList and add certain components to some sections but not others?

This is what I need

This is what I'm going for

SectionList Component

import { StyleSheet, View, Text, SafeAreaView, SectionList } from 'react-native';
import React from 'react';

const SECTIONS = [
  {
    title: 'General',
    data: [
      {
        key: '1',
        content: 'John Smith',
        desc: 'Full Name',
      },
      {
        key: '2',
        content: '[email protected]',
        desc: 'E-mail',
      },
      {
        key: '3',
        content: '(222)123-4567',
        desc: 'Phone Number'
      },
    ],
  },
  {
    title: 'Vehicles',
    data: [
      {
        key: '4',
        content: 'Honda Civic',
        desc: 'Black'
      },
      {
        key: '5',
        content: 'Jeep Wrangler',
        desc: 'White'
      },
    ],
  },
  {
    title: 'Other',
    data: [
      {
        key: '6',
        content: 'Support',
        desc: ''
      },
      {
        key: '7',
        content: 'Terms of Service',
        desc: ''
      },
      {
        key: '8',
        content: 'Deactivate Account',
        desc: ''
      },
    ],
  },
];

export default function Profile() {

  return (
    <SafeAreaView style={styles.container}>
    <SectionList
      stickySectionHeadersEnabled={false}
      sections={SECTIONS}
      // keyExtractor={(item, index) =>  item + index }
      renderSectionHeader={({section }) => (
          <Text style={styles.header}>{section.title}</Text>
      )}
      renderItem={({ item, index, section }) => (
        <View style={[
          styles.item,
          index === 0 && styles.itemFirst,
          index === section.data.length -1 && styles.itemLast
          ]}>
          <Text style={styles.title}>{item.content}</Text>
          <Text style={styles.description}>{item.desc}</Text>
        </View>
      )}
      
    />
  </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginHorizontal: 16,
  },
  item: {
    backgroundColor: '#fff',
    borderBottomColor: '#aaa',
    borderBottomWidth: 0.2,
    paddingVertical: 8,
    paddingHorizontal: 20,
    marginHorizontal: 10,
  },
  itemFirst: {
    borderTopLeftRadius: 8,
    borderTopRightRadius: 8
  },
  itemLast: {
    borderBottomLeftRadius: 8,
    borderBottomRightRadius: 8,
    borderBottomWidth: 0
  },
  header: {
    fontSize: 14,
    marginTop: 20,
    marginBottom: 10,
    marginHorizontal: 10,
    fontWeight: '400',
    color: '#333333',
    lineHeight: 24,
  },
  title: {
    fontWeight: '400',
    fontSize: 17,
    lineHeight: 22,
    color: '#000000',
    marginBottom: 1.85
  },
  description: {
    fontWeight: '400',
    fontSize: 12,
    lineHeight: 16,
    color: 'grey'
  },
  lineStyle:{
    borderWidth: 0.3,
    width: "100%",
    borderColor:'grey',
    marginTop: 7,
},
});

2

Answers


  1. A possible approach would be to introduce a field into each definition in SECTIONS, indicating the type of rendering to use (e.g. extensibleTextList, linkList etc), then switch between components. It would make sense to define a component to do the switching, but the basic idea would be equivalent to:

          renderItem={({ item, index, section }) => {
            if (section.type === "linkList")
              return <LinkItem item={item} />
            else if (section.type === "extensibleTextList")
              return <TextItem item={item} />
            // etc
          }
    

    For your "add vehicle" button, you could use a similar technique with SectionList‘s renderSectionFooter prop.

    There’s a rough illustration of the basic idea in this sandbox.

    Login or Signup to reply.
  2. You could add a switch statement inside your renderItem callback that returns a different element based on the section you’re in. However, given that:

    1. You need the list and items to behave differently in every section
    2. The sections don’t seem likely to have more than 5-10 items
    3. The sections are known ahead of time

    I would separate the logic for each section and simply map over the items. It’ll keep your SectionList from having too much responsibility, and make each section easier to change later and maintain.

    Ideally, each item would have an ID you can use as the key, rather than hard-coding the key into the list. Also, and this is purely personal preference, you could style the containers of the sections rather than each individual item.

      const general = [
          {
            content: 'John Smith',
            desc: 'Full Name',
          },
          {
            content: '[email protected]',
            desc: 'E-mail',
          },
          {
            content: '(222)123-4567',
            desc: 'Phone Number'
          },
        ];
      const vehicles = [
        // ...
      ];
      const other = [
        // ...
      ];
    
      return (
        <SafeAreaView style={styles.container}>
          {/* general section here (not shown) */}
    
          <Text style={styles.header>Vehicles</Text>
          <View style={{ borderRadius: 8, overflow: 'hidden', backgroundColor: 'white' }}>
            {vehicles.map((item, index) => {
              return (
                <View key={item.id}>
                  {index > 0 ? <View style={styles.separator} /> : null}
                  {/* rest of the item */}         
                </View>
              );
            }
            {/* footer item */}
            <TouchableOpacity onPress={addVehicle}>
              <Text>Add Vehicle</Text>
            </TouchableOpacity>
          </View>
    
          {/* etc */}
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search