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

[EXPERIMENTAL] FlashList native module experiments. #67

Draft
wants to merge 25 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7c47c34
Hybrid flashlist/legendlist operation
michbil Jan 9, 2025
e7d042e
hybrid flashlist
michbil Jan 10, 2025
6edace1
Make it work with flashlist
michbil Jan 10, 2025
6e16a6a
Fix performance issue in resetting swipable on each recycle
michbil Jan 12, 2025
91f2afd
fix typo
michbil Jan 12, 2025
201a93e
Merge remote-tracking branch 'origin/main' into hybrid/flashlist
mbilenko-florio Jan 14, 2025
54f9189
Merge branch 'fix/swipable-performance-issue' into hybrid/flashlist
mbilenko-florio Jan 14, 2025
9d4c22e
add flashlist code
mbilenko-florio Jan 14, 2025
be4f593
Make it work in a way
mbilenko-florio Jan 15, 2025
99fbef8
Working experimental Skeleton component mitigation
mbilenko-florio Jan 15, 2025
1b2a30f
Merge remote-tracking branch 'origin/main' into hybrid/flashlist
mbilenko-florio Jan 15, 2025
0f1873f
undo container change
mbilenko-florio Jan 15, 2025
67a6818
remove index-flashlist
mbilenko-florio Jan 15, 2025
0ab3f98
Make it work properly with flashlist-autolayout
mbilenko-florio Jan 15, 2025
06b662b
return original file names from FlashList
mbilenko-florio Jan 15, 2025
252a3fb
Try improve movies example
mbilenko-florio Jan 15, 2025
b0840ce
Create autolayout feedback event
mbilenko-florio Jan 16, 2025
1463356
Fix issue
mbilenko-florio Jan 16, 2025
f47afc4
add comments
mbilenko-florio Jan 17, 2025
bc5d2e2
Merge remote-tracking branch 'origin/main' into hybrid/flashlist
mbilenko-florio Jan 17, 2025
b85d03b
format
mbilenko-florio Jan 17, 2025
1afa2f1
add debug trace
mbilenko-florio Jan 17, 2025
974b7b5
revert
mbilenko-florio Jan 17, 2025
7816ce4
Merge remote-tracking branch 'origin/main' into hybrid/flashlist
mbilenko-florio Jan 29, 2025
af573e1
Use fully native scroll position
mbilenko-florio Jan 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion example/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
"experiments": {
"typedRoutes": true,
"reactCompiler": false
}
},
"autolinking": {
"searchPaths": ["../packages"]
}

}
}
18 changes: 18 additions & 0 deletions example/app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ export default function TabLayout() {
<IconSymbol size={28} name="chevron.left.forwardslash.chevron.right" color={color} />
),
}}
/>
<Tabs.Screen
name="cards-fc"
options={{
title: "Cards FL",
tabBarIcon: ({ color }) => (
<IconSymbol size={28} name="chevron.left.forwardslash.chevron.right" color={color} />
),
}}
/>
<Tabs.Screen
name="cards-fc-skel"
options={{
title: "Cards SKEL",
tabBarIcon: ({ color }) => (
<IconSymbol size={28} name="chevron.left.forwardslash.chevron.right" color={color} />
),
}}
/>
<Tabs.Screen
name="moviesL"
Expand Down
115 changes: 115 additions & 0 deletions example/app/(tabs)/cards-fc-skel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { CardSkeleton, type Item, renderItem } from "@/app/cards-renderItem";
import { DO_SCROLL_TEST, DRAW_DISTANCE, ESTIMATED_ITEM_LENGTH } from "@/constants/constants";
import { useScrollTest } from "@/constants/useScrollTest";
import { LegendList, type LegendListRef } from "@legendapp/list";
import { useRef, useState } from "react";
import { LogBox, Platform, StyleSheet, Text, View } from "react-native";

LogBox.ignoreLogs(["Open debugger"]);

interface CardsProps {
numColumns?: number;
}

export default function Cards({ numColumns = 1 }: CardsProps) {
const listRef = useRef<LegendListRef>(null);

const [data, setData] = useState<Item[]>(
() =>
Array.from({ length: 1000 }, (_, i) => ({
id: i.toString(),
})) as any[],
);

if (DO_SCROLL_TEST) {
useScrollTest((offset) => {
listRef.current?.scrollToOffset({
offset: offset,
animated: true,
});
});
}

return (
<View style={[StyleSheet.absoluteFill, styles.outerContainer]} key="legendlist">
<LegendList
ref={listRef}
style={[StyleSheet.absoluteFill, styles.scrollContainer]}
contentContainerStyle={styles.listContainer}
data={data}
renderItem={renderItem}
keyExtractor={(item) => `id${item.id}`}
estimatedItemSize={ESTIMATED_ITEM_LENGTH}
drawDistance={DRAW_DISTANCE}
//maintainVisibleContentPosition
recycleItems={true}
numColumns={numColumns}
// initialScrollIndex={50}
// alignItemsAtEnd
// maintainScrollAtEnd
// onEndReached={({ distanceFromEnd }) => {
// console.log("onEndReached", distanceFromEnd);
// }}
ListHeaderComponent={<View />}
ListHeaderComponentStyle={styles.listHeader}
ListFooterComponent={<View />}
ListFooterComponentStyle={styles.listHeader}
ListEmptyComponentStyle={{ flex: 1 }}
ListEmptyComponent={
<View style={styles.listEmpty}>
<Text style={{ color: "white" }}>Empty</Text>
</View>
}
useFlashListContainers={true}
SkeletonComponent={CardSkeleton}
waitForInitialLayout={false}
// viewabilityConfigCallbackPairs={[
// {
// viewabilityConfig: { id: "viewability", viewAreaCoveragePercentThreshold: 50 },
// // onViewableItemsChanged: ({ viewableItems, changed }) => {
// // console.log(
// // 'onViewableItems',
// // viewableItems.map((v) => v.key),
// // );
// // // console.log('onViewableChanged', changed);
// // },
// },
// ]}

// initialScrollOffset={20000}
// initialScrollIndex={500}
// inverted
// horizontal
/>
</View>
);
}

const styles = StyleSheet.create({
listHeader: {
alignSelf: "center",
height: 100,
width: 100,
backgroundColor: "#456AAA",
borderRadius: 12,
marginHorizontal: 8,
marginVertical: 8,
},
listEmpty: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#6789AB",
paddingVertical: 16,
},
outerContainer: {
backgroundColor: "#456",
bottom: Platform.OS === "ios" ? 82 : 0,
},
scrollContainer: {},
listContainer: {
width: 400,
maxWidth: "100%",
marginHorizontal: "auto",
},
});
114 changes: 114 additions & 0 deletions example/app/(tabs)/cards-fc.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { type Item, renderItem } from "@/app/cards-renderItem";
import { DO_SCROLL_TEST, DRAW_DISTANCE, ESTIMATED_ITEM_LENGTH } from "@/constants/constants";
import { useScrollTest } from "@/constants/useScrollTest";
import { LegendList, type LegendListRef } from "@legendapp/list";
import { useRef, useState } from "react";
import { LogBox, Platform, StyleSheet, Text, View } from "react-native";

LogBox.ignoreLogs(["Open debugger"]);

interface CardsProps {
numColumns?: number;
}

export default function Cards({ numColumns = 1 }: CardsProps) {
const listRef = useRef<LegendListRef>(null);

const [data, setData] = useState<Item[]>(
() =>
Array.from({ length: 1000 }, (_, i) => ({
id: i.toString(),
})) as any[],
);

if (DO_SCROLL_TEST) {
useScrollTest((offset) => {
listRef.current?.scrollToOffset({
offset: offset,
animated: true,
});
});
}

return (
<View style={[StyleSheet.absoluteFill, styles.outerContainer]} key="legendlist">
<LegendList
ref={listRef}
style={[StyleSheet.absoluteFill, styles.scrollContainer]}
contentContainerStyle={styles.listContainer}
data={data}
renderItem={renderItem}
keyExtractor={(item) => `id${item.id}`}
estimatedItemSize={ESTIMATED_ITEM_LENGTH}
drawDistance={DRAW_DISTANCE}
//maintainVisibleContentPosition
recycleItems={true}
numColumns={numColumns}
// initialScrollIndex={50}
// alignItemsAtEnd
// maintainScrollAtEnd
// onEndReached={({ distanceFromEnd }) => {
// console.log("onEndReached", distanceFromEnd);
// }}
ListHeaderComponent={<View />}
ListHeaderComponentStyle={styles.listHeader}
ListFooterComponent={<View />}
ListFooterComponentStyle={styles.listHeader}
ListEmptyComponentStyle={{ flex: 1 }}
ListEmptyComponent={
<View style={styles.listEmpty}>
<Text style={{ color: "white" }}>Empty</Text>
</View>
}
useFlashListContainers={true}
waitForInitialLayout={false}
// viewabilityConfigCallbackPairs={[
// {
// viewabilityConfig: { id: "viewability", viewAreaCoveragePercentThreshold: 50 },
// // onViewableItemsChanged: ({ viewableItems, changed }) => {
// // console.log(
// // 'onViewableItems',
// // viewableItems.map((v) => v.key),
// // );
// // // console.log('onViewableChanged', changed);
// // },
// },
// ]}

// initialScrollOffset={20000}
// initialScrollIndex={500}
// inverted
// horizontal
/>
</View>
);
}

const styles = StyleSheet.create({
listHeader: {
alignSelf: "center",
height: 100,
width: 100,
backgroundColor: "#456AAA",
borderRadius: 12,
marginHorizontal: 8,
marginVertical: 8,
},
listEmpty: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#6789AB",
paddingVertical: 16,
},
outerContainer: {
backgroundColor: "#456",
bottom: Platform.OS === "ios" ? 82 : 0,
},
scrollContainer: {},
listContainer: {
width: 400,
maxWidth: "100%",
marginHorizontal: "auto",
},
});
2 changes: 1 addition & 1 deletion example/app/(tabs)/cards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function Cards({ numColumns = 1 }: CardsProps) {
keyExtractor={(item) => `id${item.id}`}
estimatedItemSize={ESTIMATED_ITEM_LENGTH}
drawDistance={DRAW_DISTANCE}
maintainVisibleContentPosition
//maintainVisibleContentPosition
recycleItems={true}
numColumns={numColumns}
// initialScrollIndex={50}
Expand Down
2 changes: 2 additions & 0 deletions example/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,15 @@ const ListItem = ({ title, url }: ListElement) => (
);

const ListElements = () => {
console.info("App started")
return (
<SafeAreaView style={styles.container}>
<LegendList
estimatedItemSize={60}
data={data}
renderItem={({ item }) => <ListItem {...item} />}
keyExtractor={(item) => item.id.toString()}
useFlashListContainers
onItemSizeChanged={(info) => {
console.log("item size changed", info);
}}
Expand Down
5 changes: 3 additions & 2 deletions example/app/cards-flashlist/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ const styles = StyleSheet.create({
// borderBottomColor: "#ccc",
},
listContainer: {
paddingHorizontal: 16,
paddingTop: 48,
width: 400,
maxWidth: "100%",
marginHorizontal: "auto",
},
itemTitle: {
fontSize: 18,
Expand Down
35 changes: 34 additions & 1 deletion example/app/cards-renderItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const ItemCard = ({
const refSwipeable = useRef<SwipeableMethods>();

// A useState that resets when the item is recycled
const [isExpanded, setIsExpanded] = useRecyclingState ? useRecyclingState(() => false) : useState(() => false);
const [isExpanded, setIsExpanded] = useState(() => false);

const swipeableState = useRef(false);

Expand Down Expand Up @@ -262,6 +262,39 @@ export const ItemCard = ({
);
};

export const CardSkeletonBlur = () => {
return <Image style={{ height: 310, width: '100%', backgroundColor: 'blue', resizeMode: 'stretch' }} source={require('./moblur.png')} />;
}
export const CardSkeleton = () => {
return (
<View style={{ height: 300, borderRadius: 10, backgroundColor: "white", margin: 10, padding: 10 }}>
<View style={{ flexDirection: "row" }}>
<View
style={{
width: 40,
height: 40,
borderRadius: 20,
marginRight: 12,
backgroundColor: "grey",
paddingBottom: 10,
marginBottom: 15,
}}
/>
<View style={{ height: 10, backgroundColor: "#8a8a8a", margin: 5, marginBottom: 8, width: 120,borderRadius:5 }} />
</View>
<View style={{ height: 8, backgroundColor: "#8a8a8a", margin: 5, marginBottom: 8, width: 120 }} />
<View style={{ height: 10, backgroundColor: "lightgrey", margin: 5,borderRadius:5 }} />
<View style={{ height: 10, backgroundColor: "lightgrey", margin: 5,borderRadius:5 }} />
<View style={{ height: 10, backgroundColor: "lightgrey", margin: 5, borderRadius:5 }} />
<View style={{ height: 10, backgroundColor: "lightgrey", margin: 5,borderRadius:5 }} />
<View style={{ height: 10, backgroundColor: "lightgrey", margin: 5,borderRadius:5 }} />
<View style={{ height: 10, backgroundColor: "lightgrey", margin: 5,borderRadius:5 }} />
<View style={{ height: 10, backgroundColor: "lightgrey", margin: 5,borderRadius:5 }} />
<View style={{ height: 10, backgroundColor: "lightgrey", margin: 5, borderRadius:5 }} />
</View>
);
};

export const renderItem = (props: LegendListRenderItemProps<Item>) => <ItemCard {...props} />;

const styles = StyleSheet.create({
Expand Down
Binary file added example/app/moblur.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion example/app/movies-flashlist/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Movies from "@/components/Movies";

const App = () => {
return <Movies isLegend={false} />;
return <Movies isLegend={false} recycleItems={false}/>;
};

export default App;
Loading