diff --git a/fixture/react-native/src/SectionList.tsx b/fixture/react-native/src/SectionList.tsx index 3c1512118..477dda7ed 100644 --- a/fixture/react-native/src/SectionList.tsx +++ b/fixture/react-native/src/SectionList.tsx @@ -2,7 +2,7 @@ Use this component inside your React Native Application. A scrollable list with different item type */ -import React, { useMemo, useRef, useState } from "react"; +import React, { useEffect, useMemo, useRef, useState } from "react"; import { View, Text, @@ -50,21 +50,32 @@ type SectionListItem = Section | Item; export const SectionList = () => { const [refreshing, setRefreshing] = useState(false); - const [sections, setSections] = useState(generateSectionsData(10)); + const [sections, setSections] = useState(() => generateSectionsData(10)); + const refreshTimeout = useRef | null>(null); + + useEffect( + () => () => { + if (refreshTimeout.current !== null) { + clearTimeout(refreshTimeout.current); + refreshTimeout.current = null; + } + }, + [] + ); const list = useRef | null>(null); const flattenedSections = useMemo( () => - sections.reduce((acc, { index, data }) => { + sections.flatMap(({ index, data }) => { const items: Item[] = data.map((itemIndex) => ({ type: "item", index: itemIndex, sectionIndex: index, })); - return [...acc, { index, type: "section" }, ...items]; - }, []), + return [{ index, type: "section" }, ...items]; + }), [sections] ); @@ -77,28 +88,34 @@ export const SectionList = () => { ); const removeItem = (item: Item) => { - setSections( - sections.map((section) => ({ - ...section, - data: section.data.filter((index) => index === item.index), - })) - ); list.current?.prepareForLayoutAnimationRender(); + setSections((previous) => + previous.map((section) => + section.index === item.sectionIndex + ? { + ...section, + data: section.data.filter((index) => index !== item.index), + } + : section + ) + ); // after removing the item, we start animation LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); }; const removeSection = () => { - setSections(sections.slice(1)); list.current?.prepareForLayoutAnimationRender(); + setSections((previous) => previous.slice(1)); // after removing the item, we start animation LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); }; const addSection = () => { - const lastIndex = sections[sections.length - 1].index; - setSections([...sections, ...generateSectionsData(1, lastIndex + 1)]); list.current?.prepareForLayoutAnimationRender(); + setSections((previous) => { + const lastIndex = previous[previous.length - 1]?.index ?? -1; + return [...previous, ...generateSectionsData(1, lastIndex + 1)]; + }); // after removing the item, we start animation LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); }; @@ -158,15 +175,17 @@ export const SectionList = () => { ref={list} refreshing={refreshing} onRefresh={() => { + if (refreshTimeout.current !== null) return; setRefreshing(true); - setTimeout(() => { + refreshTimeout.current = setTimeout(() => { + refreshTimeout.current = null; setRefreshing(false); }, 2000); }} keyExtractor={(item) => item.type === "section" - ? `${item.index}` - : `${item.sectionIndex}${item.index}` + ? `section:${item.index}` + : `item:${item.sectionIndex}:${item.index}` } renderItem={renderItem} stickyHeaderIndices={stickyHeaderIndices} diff --git a/fixture/react-native/src/contacts/Contacts.tsx b/fixture/react-native/src/contacts/Contacts.tsx index 239f75ad9..169e3eff1 100644 --- a/fixture/react-native/src/contacts/Contacts.tsx +++ b/fixture/react-native/src/contacts/Contacts.tsx @@ -1,8 +1,8 @@ -import React, { useContext, useEffect, useMemo, useState } from "react"; +import React, { useContext, useMemo, useState } from "react"; import { FlashList } from "@shopify/flash-list"; import { ScrollView } from "react-native"; -import { DebugContext } from "../Debug"; +import { DebugContext } from "../Debug/DebugContext"; import Contact from "./models/Contact"; import contacts from "./data/contacts"; @@ -13,32 +13,21 @@ import ContactDivider from "./ContactDivider"; const Contacts = () => { const debugContext = useContext(DebugContext); - const [data, setData] = useState<(Contact | string)[]>([]); - useEffect(() => { - const contactsWithTitles = Array.from(contacts.keys()) + const [data] = useState<(Contact | string)[]>(() => + Array.from(contacts.keys()) .sort((aKey, bKey) => aKey.localeCompare(bKey)) .flatMap((key) => { return [key, ...(contacts.get(key) ?? [])]; - }); - setData(contactsWithTitles); - }, []); - - const stickyHeaderIndices = data - .map((item, index) => { - if (typeof item === "string") { - return index; - } else { - return null; - } - }) - .filter((item) => item !== null) as number[]; + }) + ); - const renderScrollComponent = useMemo(() => { - // eslint-disable-next-line react/display-name - return (props: any) => { - return ; - }; - }, []); + const stickyHeaderIndices = useMemo(() => { + const indices: number[] = []; + data.forEach((item, index) => { + if (typeof item === "string") indices.push(index); + }); + return indices; + }, [data]); return ( { if (typeof item === "string") { return ; } else { - return ; + return ; } }} getItemType={(item) => { @@ -58,7 +47,7 @@ const Contacts = () => { stickyHeaderIndices={stickyHeaderIndices} ListHeaderComponent={ContactHeader} initialScrollIndex={debugContext.initialScrollIndex} - renderScrollComponent={renderScrollComponent} + renderScrollComponent={ScrollView} /> ); }; diff --git a/fixture/react-native/src/contacts/ContactsSectionList.tsx b/fixture/react-native/src/contacts/ContactsSectionList.tsx index f37447495..b9ac83fcf 100644 --- a/fixture/react-native/src/contacts/ContactsSectionList.tsx +++ b/fixture/react-native/src/contacts/ContactsSectionList.tsx @@ -1,7 +1,7 @@ -import React, { useContext, useEffect, useState } from "react"; +import React, { useContext, useState } from "react"; import { SectionList } from "react-native"; -import { DebugContext } from "../Debug"; +import { DebugContext } from "../Debug/DebugContext"; import Contact from "./models/Contact"; import ContactSectionHeader from "./ContactSectionHeader"; @@ -17,20 +17,18 @@ interface Section { const ContactsSectionList = () => { const debugContext = useContext(DebugContext); - const [data, setData] = useState([]); - useEffect(() => { - const sectionedContacts: Section[] = Array.from(contacts.keys()) + const [data] = useState(() => + Array.from(contacts.keys()) .map((key) => { return { title: key, data: contacts.get(key) ?? [], - } as Section; + }; }) .sort((aSection, bSection) => aSection.title.localeCompare(bSection.title) - ); - setData(sectionedContacts); - }, []); + ) + ); return (