React-native: ListEmptyComponent isn't working as (I) expected

Created on 25 Jun 2017  Â·  10Comments  Â·  Source: facebook/react-native

Description

The footer component get's displayed even if the sections prop (of the SectionList) is an empty list and the empty List component never get's displayed.

Reproduction Steps

I pass down an empty list as a prop (holidays) and start async fetching the data in a parent component. Once the data is fetched I update the parent component's state and thereby the props to the child that contains the SectionList

Sample Code

footer() {
    return <Text>The End</Text>
  }

  emptyList() {
    return <Text>Fetching</Text>
  }

  render() {
    return (
      <SectionList
        style={styles.container}
        sections={this.props.holidays}
        renderItem={this.renderItem.bind(this)}
        renderSectionHeader={this.renderSectionHeader.bind(this)}
        ListFooterComponent={this.footer.bind(this)}
        ListEmptyComponent={this.emptyList.bind(this)}
      />
    )

Solution

If it's a bug then it needs to be fixed.
Else the documentation have to be update to be clear (I be gladly to help out).

Additional Information

  • react-native-cli: 2.0.1
  • react-native: 0.44.0
  • Platform: iOS
  • Development Operating System: macOS
  • Build tools: iOS 10.3
Locked

Most helpful comment

Oh! I'm sorry I haven't paid attention enough to your additional information... You're on React Native v0.44, while ListEmptyComponent has been added in 0.45.1 :)

All 10 comments

Hi @Norfeldt, I'll take a look at it as soon as possible :)
Do you have no sections or do you have no data? Basically can you clarify if your sections prop is an empty array[] or something like [{data: [], title: 'one section'}]. Thanks!

Hi @Minishlink
I pass an empty array to sections.

I clean my code a bit to make it more readable:

class ListCards extends Component {
  renderSectionHeader = ({ section }) => {
    return (
      <View style={styles.sectionHeader}>
        <Text style={{ fontSize: 18 }}>{section.key}</Text>
      </View>
    )
  }

  renderItem = ({ item }) => {
    return (
      <Card
        {...someProps}
      />
    )
  }

  footerComponent() {
    return (
      <Text style={styles.footerText}>
        The End
      </Text>
    )
  }

  emptyListComponent() {
    return <ActivityIndicator size="large" />
  }

  render() {
    return (
      <SectionList
        style={styles.container}
        sections={this.props.data}
        renderItem={this.renderItem.bind(this)}
        renderSectionHeader={this.renderSectionHeader.bind(this)}
        stickySectionHeadersEnabled={true}
        ListFooterComponent={this.footerComponent.bind(this)}
        ListEmptyComponent={this.emptyListComponent.bind(this)}
      />
    )
  }
}

Thanks for your added information :)

I just checked and the current behavior is:

  • A) if sections is an empty array ([]), the ListEmptyComponent is displayed
  • B) if sections is an array of sections with no data ([{data: [], key: 's1'}]), nothing is displayed

If you're in case A and the component is not displayed, there has to be an issue in your style or in your ListEmptyComponent...

For case B, it might indeed make sense to also display ListEmptyComponent when every sections has no data, or let users to render heterogeneously the ListEmptyComponent like renderItem...

In any way, I reckon that the documentation for SectionList's ListEmptyComponent could be improved.

Any insight @sahrens?

I'm pretty sure that it's case A, sine I in the parent element set it to be
an empty array.

I fail to see how it can be a style issue since I'm not fiddling around
with the 'visible' attribute. And regarding the component I tried to return
a simple react native 'Text' component..

On Wed, Jun 28, 2017, 22:04 Louis Lagrange notifications@github.com wrote:

Thanks for your added information :)

I just checked and the current behavior is:

  • A) if sections is an empty array ([]), the ListEmptyComponent is
    displayed
  • B) if sections is an array of sections with no data ([{data: [],
    key: 's1'}]), nothing is displayed

If you're in case A and the component is not displayed, there has to be an
issue in your style or in your ListEmptyComponent...

For case B, it might indeed make sense to also display ListEmptyComponent
when every sections has no data, or let users to render heterogeneously the
ListEmptyComponent like renderItem...

In any way, I reckon that the documentation for SectionList's
ListEmptyComponent could be improved.

Any insight @sahrens https://github.com/sahrens?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react-native/issues/14721#issuecomment-311771858,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AApbltq4Gbwyjg-0DicKicMDpQfOC6Ofks5sIrHKgaJpZM4OElaU
.

>

Venlig hilsen/Yours sincerely
Lasse Nørfeldt

I'm having the same problem. Passing an empty array to the SectionList sections prop renders the list header and footer, and doesn't render whatever is passed in the ListEmptyComponent prop.

I've had a quick look, and there is logic for rendering ListEmptyComponent in VirtualizedList here:

https://github.com/facebook/react-native/blob/master/Libraries/Lists/VirtualizedList.js#L635-L647

I can't see any similar logic in either SectionList or VirtualizedSectionList

Currently using a workaround like this:

<SectionList
  ListHeaderComponent={sections.length !== 0 ? renderHeader : renderEmpty}
  ListFooterComponent={sections.length !== 0 && renderFooter}
  ...
/>

Oh! I'm sorry I haven't paid attention enough to your additional information... You're on React Native v0.44, while ListEmptyComponent has been added in 0.45.1 :)

@Minishlink ah yes that would be why it's not working for me.

Also realised that VirtualizedSectionList renders a VirtualizedList and the ListEmptyComponent prop gets passed to it.

Thanks!

Oh! I'm sorry I haven't paid attention enough to your additional information... You're on React Native v0.44, while ListEmptyComponent has been added in 0.45.1 :)

@Minishlink this solved my problem.

Thanks!

Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:

  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the issue template.
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.

If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.

@hramos @Minishlink I dont understand the point B)

If the sections var is set as follow:

const sections = [
  {key:'hello 1', data:[{stuff:'one'}, {stuff:'two'}]},
  {key:'hello 2', data:[{stuff:'one'}, {stuff:'two'}, {stuff:'three'}]},
  {key:'hello 3', data:[{stuff:'one'}, {stuff:'two'}]},
  {key:'hello 4', data:[]}, // <--- This should create an empty row under its header?
  {key:'hello 5', data:[{stuff:'one'}, {stuff:'two'}, {stuff:'three'}, {stuff:'four'}]}
]

Is there a simple (and intuitive) way to have SectionList's empty rows below of theirs headers?
Neither the renderItem attribute nor ListEmptyComponent are triggered to render the empty row.
Not working as follow looks like a bug or, at least, looks very confusing...

Otherwise, if the ListEmptyComponent attribute is not made to create empty rows (but only empty list), maybe another new ListEmptyRowComponent attribute could be set to do the job?

The following code can be tested here
https://repl.it/N5Vk/46

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

var {height, width} = Dimensions.get('window');

export default class App extends Component {
  renderSectionHeader = ({ section }) => {
    return (
      <View style={styles.header}>
        <Text style={styles.headerText}>{section.key}</Text>
      </View>
    )
  }

  renderItem = ({ item }) => {
    return (
      <View style={styles.row}>
        <Text style={styles.rowText}>
          {item.stuff}
        </Text>
      </View>
    )
  }

  footerComponent() {
    return (
      <View style={styles.footer}>
        <Text style={styles.footerText}>
          This is the `SectionList` Footer
        </Text>
      </View>
    )
  }

  emptyListComponent() {
    return (
      <View style={styles.empty}>
        <Text style={styles.emptyText}>
          no data for this row
        </Text>
      </View>
    )
  }

  render() {
    const sections = [
      {key:'hello 1', data:[{stuff:'object one'}, {stuff:'object two'}]},
      {key:'hello 2', data:[{stuff:'object one'}, {stuff:'object two'}, {stuff:'object three'}]},
      {key:'hello 3', data:[{stuff:'object one'}, {stuff:'object two'}]},
      {key:'hello 4', data:[]}, // <--- This should create an empty row through `ListEmptyComponent` just below of its header?
      {key:'hello 5', data:[{stuff:'object one'}, {stuff:'object two'}, {stuff:'object three'}, {stuff:'object four'}]}
    ];
    return (
      <SectionList
        sections={sections}
        style={styles.container}
        renderItem={this.renderItem.bind(this)}
        renderSectionHeader={this.renderSectionHeader.bind(this)}
        stickySectionHeadersEnabled={true}
        ListFooterComponent={this.footerComponent.bind(this)}
        ListEmptyComponent={this.emptyListComponent.bind(this)}
      />
    )
  }
}

const styles = StyleSheet.create({
  container : {width, alignItems: 'center', justifyContent: 'flex-start', paddingTop: 30, backgroundColor: '#ccf0f1'},

  header    : {width, backgroundColor:'red'},
  headerText: {width, fontSize: 18, fontWeight: 'bold', textAlign: 'center', color: '#fff'},

  row       : {padding: 3, borderBottomWidth: 1, borderBottomColor: '#ccc' },
  rowText   : {fontSize: 13, fontWeight: 'normal', textAlign: 'left', color: '#333'},

  empty     : {padding: 3, backgroundColor: 'orange'},
  emptyText : {fontSize: 14, fontWeight: 'bold', textAlign: 'center', color: '#34495e'},

  footer    : {width, padding: 24, backgroundColor: 'yellow'},
  footerText: {fontSize: 18, fontWeight: 'bold', textAlign: 'center', color: '#34495e'},
});

img_3474

Was this page helpful?
0 / 5 - 0 ratings