Add toggle to switch between list impl, add default keyExtractor
This commit is contained in:
@@ -26,7 +26,10 @@ export {
|
|||||||
*
|
*
|
||||||
* - `contentOffset` - Use `headerOffset` or `footerOffset`
|
* - `contentOffset` - Use `headerOffset` or `footerOffset`
|
||||||
*/
|
*/
|
||||||
type ListProps<Item> = Omit<FlatListProps<Item>, 'contentOffset'> & {
|
type ListProps<Item extends {key: string}> = Omit<
|
||||||
|
FlatListProps<Item>,
|
||||||
|
'contentOffset'
|
||||||
|
> & {
|
||||||
/**
|
/**
|
||||||
* Wrapper around `onViewableItemsChanged` that calls back with individual
|
* Wrapper around `onViewableItemsChanged` that calls back with individual
|
||||||
* items IF they `item.isViewable` is true.
|
* items IF they `item.isViewable` is true.
|
||||||
@@ -49,7 +52,7 @@ type ListProps<Item> = Omit<FlatListProps<Item>, 'contentOffset'> & {
|
|||||||
onScrolledDownChange?: (isScrolledDown: boolean) => void
|
onScrolledDownChange?: (isScrolledDown: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const List = forwardRef(function List<Item>(
|
export const List = forwardRef(function List<Item extends {key: string}>(
|
||||||
props: ListProps<Item>,
|
props: ListProps<Item>,
|
||||||
ref: React.Ref<FlatList<Item>>,
|
ref: React.Ref<FlatList<Item>>,
|
||||||
) {
|
) {
|
||||||
@@ -126,6 +129,7 @@ export const List = forwardRef(function List<Item>(
|
|||||||
return (
|
return (
|
||||||
<Animated.FlatList
|
<Animated.FlatList
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
keyExtractor={props.keyExtractor || (i => i.key)}
|
||||||
viewabilityConfig={viewabilityConfig}
|
viewabilityConfig={viewabilityConfig}
|
||||||
onViewableItemsChanged={onViewableItemsChanged}
|
onViewableItemsChanged={onViewableItemsChanged}
|
||||||
/**
|
/**
|
||||||
@@ -150,14 +154,6 @@ export const List = forwardRef(function List<Item>(
|
|||||||
*/
|
*/
|
||||||
right: 1,
|
right: 1,
|
||||||
}}
|
}}
|
||||||
/**
|
|
||||||
* iOS-only, should match `scrollIndicatorInsets`
|
|
||||||
* @see https://reactnative.dev/docs/scrollview#contentinset-ios
|
|
||||||
*/
|
|
||||||
contentInset={{
|
|
||||||
top: props.headerOffset ?? 0,
|
|
||||||
bottom: props.footerOffset ?? 0,
|
|
||||||
}}
|
|
||||||
/**
|
/**
|
||||||
* Native only. On web, we use padding on `style` instead.
|
* Native only. On web, we use padding on `style` instead.
|
||||||
*/
|
*/
|
||||||
@@ -168,21 +164,21 @@ export const List = forwardRef(function List<Item>(
|
|||||||
refreshControl={refreshControl}
|
refreshControl={refreshControl}
|
||||||
{...(props as FlatListPropsWithLayout<Item>)}
|
{...(props as FlatListPropsWithLayout<Item>)}
|
||||||
style={[
|
style={[
|
||||||
/*
|
{
|
||||||
* On web, the List should always fill its container, otherwise
|
paddingTop: props.headerOffset,
|
||||||
* `onScroll` will not work due to the entire page scrolling.
|
paddingBottom: props.footerOffset,
|
||||||
*/
|
},
|
||||||
web([
|
web([
|
||||||
|
/*
|
||||||
|
* On web, the List should always fill its container, otherwise
|
||||||
|
* `onScroll` will not work due to the entire page scrolling.
|
||||||
|
*/
|
||||||
a.h_full,
|
a.h_full,
|
||||||
{
|
|
||||||
paddingTop: props.headerOffset,
|
|
||||||
paddingBottom: props.footerOffset,
|
|
||||||
},
|
|
||||||
]),
|
]),
|
||||||
]}
|
]}
|
||||||
onScroll={onScroll}
|
onScroll={onScroll}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}) as <Item>(
|
}) as <Item extends {key: string}>(
|
||||||
props: ListProps<Item> & {ref?: React.Ref<FlatList<Item>>},
|
props: ListProps<Item> & {ref?: React.Ref<FlatList<Item>>},
|
||||||
) => React.ReactElement
|
) => React.ReactElement
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
import {useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {runOnJS} from 'react-native-reanimated'
|
import {runOnJS} from 'react-native-reanimated'
|
||||||
|
|
||||||
|
import {List as OldList} from '#/view/com/util/List'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import {List, ListScrollProvider, useListScrollHandler} from '#/components/List'
|
import {List, ListScrollProvider, useListScrollHandler} from '#/components/List'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
@@ -36,6 +39,7 @@ type Item = {
|
|||||||
const log = (msg: any) => console.log(msg)
|
const log = (msg: any) => console.log(msg)
|
||||||
|
|
||||||
export function Inner() {
|
export function Inner() {
|
||||||
|
const [old, setOld] = useState<boolean>(false)
|
||||||
const onScrollWorklet = useListScrollHandler(e => {
|
const onScrollWorklet = useListScrollHandler(e => {
|
||||||
'worklet'
|
'worklet'
|
||||||
runOnJS(log)(`scroll ${e.contentOffset.y}`)
|
runOnJS(log)(`scroll ${e.contentOffset.y}`)
|
||||||
@@ -43,22 +47,54 @@ export function Inner() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.h_full_vh]}>
|
<View style={[a.h_full_vh]}>
|
||||||
<ListScrollProvider onScroll={onScrollWorklet}>
|
<View
|
||||||
<List<Item>
|
style={[a.fixed, a.w_full, a.py_sm, a.px_xl, a.align_center, a.z_10]}>
|
||||||
data={items}
|
<Button
|
||||||
headerOffset={100}
|
label="Toggle Old/New List"
|
||||||
footerOffset={100}
|
onPress={() => setOld(v => !v)}
|
||||||
onScrolledDownChange={scrolledDown => {
|
size="tiny"
|
||||||
console.log(`Scrolled down: ${scrolledDown}`)
|
color="primary_subtle">
|
||||||
}}
|
<ButtonText>
|
||||||
renderItem={({item}) => (
|
{old ? 'Testing old List' : 'Testing new List'}
|
||||||
<View style={[a.p_md, a.border_b]}>
|
</ButtonText>
|
||||||
<Text>{item.title}</Text>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
)}
|
|
||||||
style={[a.debug]}
|
{!old ? (
|
||||||
/>
|
<ListScrollProvider onScroll={onScrollWorklet}>
|
||||||
</ListScrollProvider>
|
<List<Item>
|
||||||
|
data={items}
|
||||||
|
headerOffset={100}
|
||||||
|
footerOffset={100}
|
||||||
|
onScrolledDownChange={scrolledDown => {
|
||||||
|
console.log(`Scrolled down: ${scrolledDown}`)
|
||||||
|
}}
|
||||||
|
renderItem={({item}) => (
|
||||||
|
<View style={[a.p_md, a.border_b]}>
|
||||||
|
<Text>{item.title}</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
style={[a.debug]}
|
||||||
|
/>
|
||||||
|
</ListScrollProvider>
|
||||||
|
) : (
|
||||||
|
<ListScrollProvider onScroll={onScrollWorklet}>
|
||||||
|
<OldList
|
||||||
|
data={items}
|
||||||
|
keyExtractor={item => item.key}
|
||||||
|
headerOffset={100}
|
||||||
|
onScrolledDownChange={scrolledDown => {
|
||||||
|
console.log(`Scrolled down: ${scrolledDown}`)
|
||||||
|
}}
|
||||||
|
renderItem={({item}) => (
|
||||||
|
<View style={[a.p_md, a.border_b]}>
|
||||||
|
<Text>{item.title}</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
style={[a.debug]}
|
||||||
|
/>
|
||||||
|
</ListScrollProvider>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user