Skip to content

FlatList's renderItem renders twice, instead of once #18396

@TheDutchCoder

Description

@TheDutchCoder

When using a FlatList and you're using the renderItem method to create an "inline" list item, it will be rendered twice, instead of once on a data change.

Environment

Environment:
  OS: macOS High Sierra 10.13.3
  Node: 4.8.2
  Yarn: Not Found
  npm: 4.6.1
  Watchman: Not Found
  Xcode: Xcode 9.2 Build version 9C40b
  Android Studio: Not Found

Packages: (wanted => installed)
  react: 16.2.0 => 16.2.0
  react-native: 0.53.0 => 0.53.0

Expected Behavior

List items should be re-rendered only once, not twice when the data property changes.

Actual Behavior

All items are re-rendered twice.

Steps to Reproduce

https://snack.expo.io/HkCbeluKG

Source

import React, { Component } from 'react';
import { Text, FlatList } from 'react-native';

export default class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      foo: [{ id: '1', name: 'one' }],
      bar: []
    }

    setTimeout(() => {
      this.setState({
        foo: [{ id: '1', name: 'one' }, { id: '2', name: 'two' }]
      })
    }, 1000)
  }

  componentDidMount() {
    console.log('mounted FlatList')
  }

  _keyExtractor = (item) => item.id

  _renderItem = ({item}) => {
    console.log(`rendering ${item.name}`) // This should fire only once when this.state.foo changes!
    return (
      <Text>{item.name}</Text>
    )
  }

  render() {
    return (
      <FlatList
        data={this.state.foo}
        extraData={this.state.bar}
        renderItem={this._renderItem}
        keyExtractor={this._keyExtractor}
      />
    )
  }
}

Working source

When using a PureComponent instead, it works as expected:

class ListItem extends React.PureComponent {
  constructor(props) {
    super(props)

    console.log(`created ListItem ${this.props.name}`)
  }

  componentDidUpdate() {
    console.log(`updated ListItem ${this.props.name}`)
  }

  render() {
    return (
      <Text>{this.props.name}</Text>
    )
  }
}

class PhotoPickerScreen extends React.Component {

  constructor(props) {
    super(props)

    this.state = {
      foo: [{ id: '1', name: 'one' }],
      bar: []
    }

    setTimeout(() => {
      this.setState({
        foo: [{ id: '1', name: 'one' }, { id: '2', name: 'two' }]
      })
    }, 1000)
  }

  componentDidMount() {
    console.log('mounted FlatList')
  }

  _keyExtractor = (item) => item.id

  _renderItem = ({item}) => (
    <ListItem name={item.name} />
  )

  render() {
    return (
      <FlatList
        data={this.state.foo}
        extraData={this.state.bar}
        renderItem={this._renderItem}
        keyExtractor={this._keyExtractor}
      />
    )
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Ran CommandsOne of our bots successfully processed a command.Resolution: LockedThis issue was locked by the bot.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions