如何在React Native的SectionList的每个部分中使用不同类型的组件?

huangapple go评论56阅读模式
英文:

How to have different types of components in each section of a React Native SectionList?

问题

我有一个SectionList分为3个部分:

  1. 普通用户信息
  2. 用户车辆信息
  3. 其他选项

普通信息项需要是TouchableOpacity组件,以便用户点击时,可以跳转到更新页面以更新这些数据。

车辆信息项只是文本组件,但我确实需要一个“添加车辆”按钮组件始终显示在此部分的末尾,无论添加了多少车辆。

其他选项部分可以都是TouchableOpacity组件,重定向到应用程序中的不同页面。

我该如何在SectionList的不同部分中呈现不同的组件,并在某些部分但不在其他部分添加特定的组件?

我需要的是这样的效果

如何在React Native的SectionList的每个部分中使用不同类型的组件?

英文:

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

如何在React Native的SectionList的每个部分中使用不同类型的组件?

> 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: 'john.smith@gmail.com',
        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,
},
});

答案1

得分: 0

以下是翻译好的部分:

一个可能的方法是在SECTIONS中的每个定义中引入一个字段,指示要使用的呈现type(例如extensibleTextListlinkList等),然后在组件之间进行切换。定义一个组件来执行切换是有意义的,但基本思想等效于:

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

对于您的“添加车辆”按钮,您可以使用类似的技巧,使用SectionListrenderSectionFooter属性。

此沙箱中有一个基本思想的粗略示例。

英文:

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 }) =&gt; {
        if (section.type === &quot;linkList&quot;)
          return &lt;LinkItem item={item} /&gt;
        else if (section.type === &quot;extensibleTextList&quot;)
          return &lt;TextItem item={item} /&gt;
        // 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.

答案2

得分: 0

你可以在你的renderItem回调内添加一个switch语句,根据所在的部分返回不同的元素。然而,鉴于:

  1. 你需要在每个部分中使列表和项的行为不同
  2. 这些部分似乎不太可能有超过5-10个项
  3. 部分是提前知道的

我会将每个部分的逻辑分开,并简单地映射项。这样可以保持你的SectionList不负担太多责任,并使每个部分稍后更容易更改和维护。

理想情况下,每个项都应该有一个ID,你可以将其用作键,而不是将键硬编码到列表中。此外,这纯粹是个人偏好,你可以为部分的容器添加样式,而不是每个单独的项。

  const general = [
      {
        content: 'John Smith',
        desc: 'Full Name',
      },
      {
        content: 'john.smith@gmail.com',
        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}
              {/* 其余的项 */}
            </View>
          );
        })}
        {/* 底部项 */}
        <TouchableOpacity onPress={addVehicle}>
          <Text>Add Vehicle</Text>
        </TouchableOpacity>
      </View>

      {/* 等等 */}
    </SafeAreaView>
  );
英文:

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: &#39;John Smith&#39;,
        desc: &#39;Full Name&#39;,
      },
      {
        content: &#39;john.smith@gmail.com&#39;,
        desc: &#39;E-mail&#39;,
      },
      {
        content: &#39;(222)123-4567&#39;,
        desc: &#39;Phone Number&#39;
      },
    ];
  const vehicles = [
    // ...
  ];
  const other = [
    // ...
  ];

  return (
    &lt;SafeAreaView style={styles.container}&gt;
      {/* general section here (not shown) */}

      &lt;Text style={styles.header&gt;Vehicles&lt;/Text&gt;
      &lt;View style={{ borderRadius: 8, overflow: &#39;hidden&#39;, backgroundColor: &#39;white&#39; }}&gt;
        {vehicles.map((item, index) =&gt; {
          return (
            &lt;View key={item.id}&gt;
              {index &gt; 0 ? &lt;View style={styles.separator} /&gt; : null}
              {/* rest of the item */}         
            &lt;/View&gt;
          );
        }
        {/* footer item */}
        &lt;TouchableOpacity onPress={addVehicle}&gt;
          &lt;Text&gt;Add Vehicle&lt;/Text&gt;
        &lt;/TouchableOpacity&gt;
      &lt;/View&gt;

      {/* etc */}

huangapple
  • 本文由 发表于 2023年4月16日 23:51:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76028783.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定