Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First Sticky header gets duplicated if ListHeaderComponent is set #1527

Open
2 tasks done
vendramini opened this issue Feb 21, 2025 · 4 comments
Open
2 tasks done

First Sticky header gets duplicated if ListHeaderComponent is set #1527

vendramini opened this issue Feb 21, 2025 · 4 comments
Labels
bug Something isn't working

Comments

@vendramini
Copy link

Current behavior

It started happening after I've enabled new RN architecture on Expo 52.

const stickyHeaderIndices = filteredList
    .map((item, index) => {
      if (typeof item === 'string') {
        return index;
      } else {
        return null;
      }
    })
    .filter((item) => item !== null);

  content = (
    <FlashList
      ListHeaderComponent={() => {
        return(
          <Text>ListHeaderComponent here!</Text>
        );
      }}
      ItemSeparatorComponent={() => <DefaultListRowSeparator />}
      contentContainerStyle={styles.contentContainer}
      estimatedItemSize={moderateScale(60)}
      getItemType={(item) => {
        return typeof item === 'string' ? 'sectionHeader' : 'row';
      }}
      stickyHeaderIndices={stickyHeaderIndices}
      data={filteredList}
      renderItem={({ item, target }) => {
        if (typeof item === 'string') {
          return (
            <Text fontFamily={'Poppins_500Medium'} style={styles.sectionHeader(target === 'StickyHeader')}>
              {item}
            </Text>
          );
        } else {
          return (
            <RowLink
              label={item.title}
            />
          );
        }
      }}
    />
  );

Image

If I touch the list the problem gets fixed:

Image

Expected behavior

Do not duplicate the first sticky item on top of ListHeaderComponent.

To Reproduce

Platform:

  • iOS
  • Android

Environment

1.7.3

@vendramini vendramini added the bug Something isn't working label Feb 21, 2025
@mensonones
Copy link

Bug version of stickyHeaderIndices

const stickyHeaderIndices = contacts
    .map((item, index) => {
        if (typeof item === "string") {
            return index;
        } else {
            return null;
        }
    })
    .filter((item) => item !== null) as number[];

Proposal fix duplication

const stickyHeaderIndices = contacts
    .map((item, index) => (typeof item === "string" ? index + 1 : null))
    .filter((item) => item !== null) as number[];

Complete code

import React from "react";
import { StyleSheet, Text, View } from "react-native";
import { FlashList } from "@shopify/flash-list";
import { SafeAreaView } from "react-native-safe-area-context";

interface Contact {
  firstName: string;
  lastName: string;
}

const contacts: (string | Contact)[] = [
  "A",
  { firstName: "Arron", lastName: "Adams" },
  "B",
  { firstName: "Bob", lastName: "Baker" },
  { firstName: "Bill", lastName: "Baker" },
  "C",
  { firstName: "Charlie", lastName: "Carter" },
  { firstName: "Cathy", lastName: "Carter" },
  { firstName: "Cameron", lastName: "Carter" },
  "D",
  { firstName: "David", lastName: "Williams" },
  { firstName: "Diana", lastName: "Perez" },
  { firstName: "Derek", lastName: "Johnson" },
  "E",
  { firstName: "Eva", lastName: "Martinez" },
  { firstName: "Ella", lastName: "Moore" },
  { firstName: "Ethan", lastName: "Brown" },
  "F",
  { firstName: "Fiona", lastName: "Garcia" },
  { firstName: "Frank", lastName: "Martinez" },
];

/* Bug version
const stickyHeaderIndices = contacts
  .map((item, index) => {
    if (typeof item === "string") {
      return index;
    } else {
      return null;
    }
  })
  .filter((item) => item !== null) as number[]; 
*/

const stickyHeaderIndices = contacts
  .map((item, index) => (typeof item === "string" ? index + 1 : null))
  .filter((item) => item !== null) as number[];

const App = () => {
  return (
    <View style={{ flex: 1 }}>
      <SafeAreaView />
      <FlashList
        ListHeaderComponent={
          <Text style={{ fontSize: 32, padding: 16, color: "#FFFFFF" }}>
            Contacts
          </Text>
        }
        data={contacts}
        renderItem={({ item }) => {
          if (typeof item === "string") {
            // Rendering header
            return <Text style={styles.header}>{item}</Text>;
          } else {
            // Render item
            return (
              <Text
                style={{
                  color: "#FFFFFF",
                  fontSize: 24,
                  padding: 16,
                  borderBottomWidth: 1,
                  borderBottomColor: "#ccc",
                }}
              >
                {item.firstName} {item.lastName}
              </Text>
            );
          }
        }}
        stickyHeaderIndices={stickyHeaderIndices}
        getItemType={(item) => {
          // To achieve better performance, specify the type based on the item
          return typeof item === "string" ? "sectionHeader" : "row";
        }}
        estimatedItemSize={100}
      />
    </View>
  );
};

export default App;

const styles = StyleSheet.create({
  header: {
    fontSize: 32,
    backgroundColor: "#fff",
  },
});

Could you try this proposed solution?

@vendramini
Copy link
Author

Hey, thank you for your suggestion! However, I couldn't understand what you've tried to achieve. The sticky indices should be the ones we want to get fixed on top, you are changing then by adding 1. Can you elaborate, please? It didn't work out.

I'll try to setup a demo asap.

@mensonones
Copy link

Hey, thank you for your suggestion! However, I couldn't understand what you've tried to achieve. The sticky indices should be the ones we want to get fixed on top, you are changing then by adding 1. Can you elaborate, please? It didn't work out.

I'll try to setup a demo asap.

I tried to reproduce the problem with this code example. If you uncomment stickyHeaderIndices from the example and comment out the current version, the bug will occur.

The problem occurs because FlashList tries to pin the "A" header to the top (since it is at index 0), but the ListHeaderComponent ("Contacts") is already at the top of the list. Instead of replacing or rendering them together, FlashList ends up rendering both at the same time, creating the duplication.

it could just be a problem in the logic used to generate the stickyHeaderIndices array.

If you provide an example more faithful to your case, I can look at it later. :)

@vendramini
Copy link
Author

I've recompiled my app using the old architecture and it gets back working as expected. So it's related to the new architecture.

This library doesn't seem to be prepared to use new architecture yet, as we can see more issues related to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants