react / react/react-native

SectionList unnecessarily unmounts and mounts items when filtering (in between renders)

Open
#28,919 25 comments 15 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Component: SectionList Needs: Attention Platform: Android
Dominant language
C++
Stars
127k
Forks
25.3k
Avg merge
1d 23h
Merged PRs (30d)
4

Description

Description

When a SectionList rerenders, sometimes it unmounts and remounts some of its items unnecessarily, even though the items preserve the same "key" prop in between renders. This impacts performance.

A scenario where this could happen is when filtering data. Imagine a SectionList with a search bar (TextInput) above it. Every time the user types something in the search bar, the section list gets filtered so it shows the items that contain the text in the search bar. Sometimes, the items get remounted unnecessarily when typing (Why remount an item when it was already there? It passed the filter, it should stay there.)

React Native version:

System:
OS: Windows 10 10.0.18363
CPU: (8) x64 Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
Memory: 6.52 GB / 15.87 GB
Binaries:
Node: 12.14.0 - C:\Program Files\nodejs\node.EXE
Yarn: Not Found
npm: 6.13.4 - C:\Program Files\nodejs\npm.CMD
Watchman: Not Found
SDKs:
Android SDK: Not Found
IDEs:
Android Studio: Version 3.6.0.0 AI-192.7142.36.36.6392135
Languages:
Java: Not Found
Python: 2.7.17 - C:\Python27\python.EXE
npmPackages:
@react-native-community/cli: Not Found
react: 16.11.0 => 16.11.0
react-native: 0.62.2 => 0.62.2
npmGlobalPackages:
react-native: Not Found

Steps To Reproduce

  1. Create a new react-native project. npx react-native init sectionlisttest
  2. Modify the App.js file so it looks like the following.
import React, {useEffect, useState} from 'react';
import {SectionList, Text, View} from 'react-native';

const originalData = [{
  key: 'header1',
  header: 'Header 1',
  data: [{key: 'firstItem'}, {key: 'byebye1'}],
}];

const filteredData = [{
  key: 'header1',
  header: 'Header 1',
  data: [{key: 'firstItem'}],
}];

export default function App() {
  useEffect(() => {
    setTimeout(() => setSections(filteredData), 5000);
  }, []);

  const [sections, setSections] = useState(originalData);

  return (
    <SectionList
      sections={sections}
      renderItem={renderItem}
      renderSectionHeader={renderSectionHeader}
      ItemSeparatorComponent={Separator}
    />
  );
}

const renderItem = ({item}) => <Item item={item} />;

const Item = ({item}) => {
  useEffect(() => {
    console.log('item mounted');
  }, []);
  return <Text>{item.key}</Text>;
};

const renderSectionHeader = ({section}) => <Text>{section.header}</Text>;

const Separator = () => <View style={{height: 1, backgroundColor: 'black'}} />;
  1. Run the app. I ran it in Android (npx react-native run-android).

IMPORTANT: Fully reload the app, don't depend on hot reloading.

Expected Results

Expected result: 2 lines saying "Item mounted" get printed to the logs.

Actual Result: 2 lines saying "Item mounted" get printed to the logs. . But then, 5 seconds later, it prints a third line also saying "Item mounted".

Snack, code example, screenshot, or link to a repository:

Snack: https://snack.expo.io/@hectorricardo/sectionlist-bug

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the behavior from the App.js example or the linked Snack, using the SectionList data transition after five seconds. Trace which items mount during the update and review the SectionList rendering behavior and key handling. Done means filtering or updating sections no longer mounts an item that retains the same key unnecessarily, with a regression test covering the scenario.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react-native
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.