diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5e248e34..4f25438d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -24,7 +24,7 @@
"editor.formatOnSave": true,
"editor.defaultFormatter": "astro-build.astro-vscode"
},
- "cSpell.words": ["Flashlist", "Lato"],
+ "cSpell.words": ["Legendlist", "Lato"],
"i18n-ally.localesPaths": ["src/translations/"],
"i18n-ally.keystyle": "nested",
"i18n-ally.disabled": false, // make sure to disable i18n-ally in your global setting and only enable it for such projects
diff --git a/README.md b/README.md
index 649f0fd1..1e2f4b4d 100644
--- a/README.md
+++ b/README.md
@@ -93,7 +93,7 @@ We value the feedback and contributions of our users, and we encourage you to le
- [Expo](https://docs.expo.io/)
- [Expo Router](https://docs.expo.dev/router/introduction/)
- [Nativewind](https://www.nativewind.dev/v4/overview)
-- [Flash list](https://github.com/Shopify/flash-list)
+- [Legend list](https://github.com/LegendApp/legend-list)
- [React Query](https://tanstack.com/query/v4)
- [Axios](https://axios-http.com/docs/intro)
- [React Hook Form](https://react-hook-form.com/)
diff --git a/cli/README.md b/cli/README.md
index efa649dd..f1803574 100644
--- a/cli/README.md
+++ b/cli/README.md
@@ -104,7 +104,7 @@ We value the feedback and contributions of our users, and we encourage you to le
- [Expo](https://docs.expo.io/)
- [Expo Router](https://docs.expo.dev/router/introduction/)
- [Nativewind](https://www.nativewind.dev/)
-- [Flash list](https://github.com/Shopify/flash-list)
+- [Legend List](https://github.com/LegendApp/legend-list)
- [React Query](https://tanstack.com/query/v4)
- [Axios](https://axios-http.com/docs/intro)
- [React Hook Form](https://react-hook-form.com/)
diff --git a/docs/src/content/docs/overview.md b/docs/src/content/docs/overview.md
index 39350040..3d6a7af5 100644
--- a/docs/src/content/docs/overview.md
+++ b/docs/src/content/docs/overview.md
@@ -89,7 +89,7 @@ We value the feedback and contributions of our users, and we encourage you to le
- [Expo](https://docs.expo.io/)
- [Expo Router](https://docs.expo.dev/router/introduction/)
- [Nativewind](https://www.nativewind.dev/v4/overview)
-- [Flash list](https://github.com/Shopify/flash-list)
+- [Legend List](https://github.com/LegendApp/legend-list)
- [React Query](https://tanstack.com/query/v4)
- [Axios](https://axios-http.com/docs/intro)
- [React Hook Form](https://react-hook-form.com/)
diff --git a/package.json b/package.json
index 01443205..fa3da87c 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
"@expo/metro-runtime": "^4.0.1",
"@gorhom/bottom-sheet": "^5.0.5",
"@hookform/resolvers": "^3.9.0",
- "@shopify/flash-list": "1.7.3",
+ "@legendapp/list": "^2.0.0",
"@tanstack/react-query": "^5.52.1",
"app-icon-badge": "^0.1.2",
"axios": "^1.7.5",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 122e3a54..db2e555c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,9 +17,9 @@ importers:
'@hookform/resolvers':
specifier: ^3.9.0
version: 3.9.0(react-hook-form@7.53.0(react@18.3.1))
- '@shopify/flash-list':
- specifier: 1.7.3
- version: 1.7.3(@babel/runtime@7.26.0)(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1)
+ '@legendapp/list':
+ specifier: ^2.0.0
+ version: 2.0.0(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1)
'@tanstack/react-query':
specifier: ^5.52.1
version: 5.52.1(react@18.3.1)
@@ -1544,6 +1544,12 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ '@legendapp/list@2.0.0':
+ resolution: {integrity: sha512-GOh1x9U0VE5zCcZ/sDyvCBKyvA4ZQMOOKipWFxHdlURYATC1gs9TLVrBAO3gENgG1b0VlllUIr7foxGFj/tHoA==}
+ peerDependencies:
+ react: '*'
+ react-native: '*'
+
'@motionone/animation@10.18.0':
resolution: {integrity: sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==}
@@ -1780,13 +1786,6 @@ packages:
'@segment/loosely-validate-event@2.0.0':
resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==}
- '@shopify/flash-list@1.7.3':
- resolution: {integrity: sha512-RLhNptm02aqpqZvjj9pJPcU+EVYxOAJhPRCmDOaUbUP86+636w+plsbjpBPSYGvPZhPj56RtZ9FBlvolPeEmYA==}
- peerDependencies:
- '@babel/runtime': '*'
- react: '*'
- react-native: '*'
-
'@sinclair/typebox@0.27.8':
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
@@ -4961,9 +4960,11 @@ packages:
lodash.get@4.4.2:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
+ deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+ deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
@@ -6114,12 +6115,6 @@ packages:
resolution: {integrity: sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==}
engines: {node: '>= 4'}
- recyclerlistview@4.2.1:
- resolution: {integrity: sha512-NtVYjofwgUCt1rEsTp6jHQg/47TWjnO92TU2kTVgJ9wsc/ely4HnizHHa+f/dI7qaw4+zcSogElrLjhMltN2/g==}
- peerDependencies:
- react: '>= 15.2.1'
- react-native: '>= 0.30.0'
-
redent@3.0.0:
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
engines: {node: '>=8'}
@@ -6900,9 +6895,6 @@ packages:
esbuild:
optional: true
- ts-object-utils@0.0.5:
- resolution: {integrity: sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA==}
-
tsconfig-paths@3.15.0:
resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
@@ -7082,6 +7074,11 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ use-sync-external-store@1.5.0:
+ resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
utif2@4.1.0:
resolution: {integrity: sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==}
@@ -9352,6 +9349,12 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
+ '@legendapp/list@2.0.0(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ react: 18.3.1
+ react-native: 0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1)
+ use-sync-external-store: 1.5.0(react@18.3.1)
+
'@motionone/animation@10.18.0':
dependencies:
'@motionone/easing': 10.18.0
@@ -9702,14 +9705,6 @@ snapshots:
component-type: 1.2.2
join-component: 1.1.0
- '@shopify/flash-list@1.7.3(@babel/runtime@7.26.0)(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@babel/runtime': 7.26.0
- react: 18.3.1
- react-native: 0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1)
- recyclerlistview: 4.2.1(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1)
- tslib: 2.8.1
-
'@sinclair/typebox@0.27.8': {}
'@sinonjs/commons@3.0.1':
@@ -11428,7 +11423,7 @@ snapshots:
debug: 4.3.7
enhanced-resolve: 5.17.1
eslint: 8.57.0
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.8.1
is-bun-module: 1.2.1
@@ -11447,20 +11442,20 @@ snapshots:
debug: 4.3.7
enhanced-resolve: 5.17.1
eslint: 8.57.0
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.8.1
is-bun-module: 1.2.1
is-glob: 4.0.3
optionalDependencies:
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
transitivePeerDependencies:
- '@typescript-eslint/parser'
- eslint-import-resolver-node
- eslint-import-resolver-webpack
- supports-color
- eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0):
+ eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -11471,14 +11466,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0):
+ eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.3.3)
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0)
+ eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0)
transitivePeerDependencies:
- supports-color
@@ -11518,7 +11513,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3
@@ -11547,7 +11542,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3
@@ -14939,14 +14934,6 @@ snapshots:
source-map: 0.6.1
tslib: 2.8.1
- recyclerlistview@4.2.1(react-native@0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1))(react@18.3.1):
- dependencies:
- lodash.debounce: 4.0.8
- prop-types: 15.8.1
- react: 18.3.1
- react-native: 0.76.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(react@18.3.1)
- ts-object-utils: 0.0.5
-
redent@3.0.0:
dependencies:
indent-string: 4.0.0
@@ -15754,8 +15741,6 @@ snapshots:
'@jest/types': 29.6.3
babel-jest: 29.7.0(@babel/core@7.26.0)
- ts-object-utils@0.0.5: {}
-
tsconfig-paths@3.15.0:
dependencies:
'@types/json5': 0.0.29
@@ -15918,6 +15903,10 @@ snapshots:
dependencies:
react: 18.3.1
+ use-sync-external-store@1.5.0(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+
utif2@4.1.0:
dependencies:
pako: 1.0.11
diff --git a/src/app/(app)/index.tsx b/src/app/(app)/index.tsx
index 9e69163e..692ec111 100644
--- a/src/app/(app)/index.tsx
+++ b/src/app/(app)/index.tsx
@@ -1,15 +1,21 @@
-import { FlashList } from '@shopify/flash-list';
+import { type LegendListRenderItemProps } from '@legendapp/list';
import React from 'react';
import type { Post } from '@/api';
import { usePosts } from '@/api';
import { Card } from '@/components/card';
-import { EmptyList, FocusAwareStatusBar, Text, View } from '@/components/ui';
+import {
+ EmptyList,
+ FocusAwareStatusBar,
+ List,
+ Text,
+ View,
+} from '@/components/ui';
export default function Feed() {
const { data, isPending, isError } = usePosts();
const renderItem = React.useCallback(
- ({ item }: { item: Post }) => ,
+ ({ item }: LegendListRenderItemProps) => ,
[]
);
@@ -23,12 +29,16 @@ export default function Feed() {
return (
- `item-${index}`}
+ keyExtractor={(item: Post, index: number) =>
+ item.id?.toString() || `item-${index}`
+ }
ListEmptyComponent={}
estimatedItemSize={300}
+ recycleItems
+ maintainVisibleContentPosition
/>
);
diff --git a/src/components/ui/list.tsx b/src/components/ui/list.tsx
index 68ebc724..edf21f72 100644
--- a/src/components/ui/list.tsx
+++ b/src/components/ui/list.tsx
@@ -1,4 +1,4 @@
-import { FlashList as NFlashList } from '@shopify/flash-list';
+import { LegendList } from '@legendapp/list';
import React from 'react';
import { ActivityIndicator, View } from 'react-native';
import Svg, { Circle, Path } from 'react-native-svg';
@@ -8,7 +8,7 @@ type Props = {
isLoading: boolean;
};
-export const List = NFlashList;
+export const List = LegendList;
export const EmptyList = React.memo(({ isLoading }: Props) => {
return (
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
index 2d82b166..d50d04b7 100644
--- a/src/components/ui/select.tsx
+++ b/src/components/ui/select.tsx
@@ -3,7 +3,7 @@ import {
BottomSheetFlatList,
type BottomSheetModal,
} from '@gorhom/bottom-sheet';
-import { FlashList } from '@shopify/flash-list';
+import { LegendList } from '@legendapp/list';
import { useColorScheme } from 'nativewind';
import * as React from 'react';
import type { FieldValues } from 'react-hook-form';
@@ -56,7 +56,7 @@ const selectTv = tv({
},
});
-const List = Platform.OS === 'web' ? FlashList : BottomSheetFlatList;
+const List = Platform.OS === 'web' ? LegendList : BottomSheetFlatList;
export type OptionType = { label: string; value: string | number };