Search code examples
reactjsreact-nativereact-native-iosreact-native-sectionlist

SectionList creating a separate renderItem for each character of a string


I'm trying to use a SectionList to print the key/value pairs of an object. However, values which are strings are rendered character by character by the renderItem.

Code:


const mainObject = {
 "key1": "val1",
 "key2": ["val2.0","val2.1"],
 "key3": "val3",
}

const renderItem = ({item}) => <Text>{item}</Text>

const sectionHeader = ({section}) => (
    <Text style={{fontWeight: "bold"}}>{section.title}</Text>);

//Object.entries(obj) returns an array [["key0","value0"],["key1","value1"]
//for all the key value pairs in the object

const sections = (obj) => Object.entries(obj).map((val) => ({
    data: val[1],
    title: val[0],
}))


const ObjectList = props => (
    <SectionList
        renderItem={renderItem}
        renderSectionHeader={sectionHeader}
        sections={sections(mainObject)}
        keyExtractor={(item, index) => item + index}
    >
    </SectionList>
)

The output on the screen is:

key1
v
a
l
1

key2
val2.0
val2.1

key3
v
a
l
3

To fix the problem, I have put the strings into Arrays and so Strings inside arrays are printed properly, but I was just wondering why they need to be nested inside an array for the whole string to be printed on on one row?

const sections = (obj) => Object.entries(obj).map((val) => ({

    //checks if the value is an array, if not then nest that value
    //inside the array otherwise leave it as it is

    data: !Array.isArray(val[1]) ? [val[1]] : val[1],
    title: val[0],
}))

Solution

  • The data key in the sections prop is expected to be a list of items to render in the section. Your code above ends up with something like:

    const sections = [
      {title: 'key1': data: 'val1'},
      ...
    ]
    

    when val[1] is a string.

    So the SectionList is iterating over data, which is just a string, to create each item under that section heading, hence you get each character. If val[1] may be a string or may be an array of strings then you're doing the correct thing by wrapping it in an array if necessary.

    If you have control over how mainObject is created you probably want to wrap the vals beforehand:

    const mainObject = {
     "key1": ["val1"],
     "key2": ["val2.0","val2.1"],
     "key3": ["val3"],
    }