Address lint warnings in List.web.tsx (#10046)
This commit is contained in:
@@ -1,9 +1,13 @@
|
|||||||
import React, {
|
import {
|
||||||
|
forwardRef,
|
||||||
isValidElement,
|
isValidElement,
|
||||||
type JSX,
|
|
||||||
memo,
|
memo,
|
||||||
startTransition,
|
startTransition,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
useRef,
|
useRef,
|
||||||
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import {
|
import {
|
||||||
type FlatListProps,
|
type FlatListProps,
|
||||||
@@ -39,7 +43,7 @@ export type ListProps<ItemT> = Omit<
|
|||||||
*/
|
*/
|
||||||
sideBorders?: boolean
|
sideBorders?: boolean
|
||||||
}
|
}
|
||||||
export type ListRef = React.MutableRefObject<any | null> // TODO: Better types.
|
export type ListRef = React.RefObject<View>
|
||||||
|
|
||||||
const ON_ITEM_SEEN_WAIT_DURATION = 0.5e3 // when we consider post to be "seen"
|
const ON_ITEM_SEEN_WAIT_DURATION = 0.5e3 // when we consider post to be "seen"
|
||||||
const ON_ITEM_SEEN_INTERSECTION_OPTS = {
|
const ON_ITEM_SEEN_INTERSECTION_OPTS = {
|
||||||
@@ -77,7 +81,7 @@ function ListImpl<ItemT>(
|
|||||||
|
|
||||||
const isEmpty = !data || data.length === 0
|
const isEmpty = !data || data.length === 0
|
||||||
|
|
||||||
let headerComponent: JSX.Element | null = null
|
let headerComponent: React.JSX.Element | null = null
|
||||||
if (ListHeaderComponent != null) {
|
if (ListHeaderComponent != null) {
|
||||||
if (isValidElement(ListHeaderComponent)) {
|
if (isValidElement(ListHeaderComponent)) {
|
||||||
headerComponent = ListHeaderComponent
|
headerComponent = ListHeaderComponent
|
||||||
@@ -87,7 +91,7 @@ function ListImpl<ItemT>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let footerComponent: JSX.Element | null = null
|
let footerComponent: React.JSX.Element | null = null
|
||||||
if (ListFooterComponent != null) {
|
if (ListFooterComponent != null) {
|
||||||
if (isValidElement(ListFooterComponent)) {
|
if (isValidElement(ListFooterComponent)) {
|
||||||
footerComponent = ListFooterComponent
|
footerComponent = ListFooterComponent
|
||||||
@@ -97,7 +101,7 @@ function ListImpl<ItemT>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let emptyComponent: JSX.Element | null = null
|
let emptyComponent: React.JSX.Element | null = null
|
||||||
if (ListEmptyComponent != null) {
|
if (ListEmptyComponent != null) {
|
||||||
if (isValidElement(ListEmptyComponent)) {
|
if (isValidElement(ListEmptyComponent)) {
|
||||||
emptyComponent = ListEmptyComponent
|
emptyComponent = ListEmptyComponent
|
||||||
@@ -113,9 +117,9 @@ function ListImpl<ItemT>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getScrollableNode = React.useCallback(() => {
|
const getScrollableNode = useCallback(() => {
|
||||||
if (disableFullWindowScroll) {
|
if (disableFullWindowScroll) {
|
||||||
const element = nativeRef.current as HTMLDivElement | null
|
const element = nativeRef.current
|
||||||
if (!element) return
|
if (!element) return
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -186,8 +190,8 @@ function ListImpl<ItemT>(
|
|||||||
}
|
}
|
||||||
}, [disableFullWindowScroll])
|
}, [disableFullWindowScroll])
|
||||||
|
|
||||||
const nativeRef = React.useRef<HTMLDivElement>(null)
|
const nativeRef = useRef<HTMLDivElement>(null)
|
||||||
React.useImperativeHandle(
|
useImperativeHandle(
|
||||||
ref,
|
ref,
|
||||||
() =>
|
() =>
|
||||||
({
|
({
|
||||||
@@ -226,7 +230,7 @@ function ListImpl<ItemT>(
|
|||||||
useResizeObserver(containerRef, onContentSizeChange)
|
useResizeObserver(containerRef, onContentSizeChange)
|
||||||
|
|
||||||
// --- onScroll ---
|
// --- onScroll ---
|
||||||
const [isInsideVisibleTree, setIsInsideVisibleTree] = React.useState(false)
|
const [isInsideVisibleTree, setIsInsideVisibleTree] = useState(false)
|
||||||
const handleScroll = useNonReactiveCallback(() => {
|
const handleScroll = useNonReactiveCallback(() => {
|
||||||
if (!isInsideVisibleTree) return
|
if (!isInsideVisibleTree) return
|
||||||
|
|
||||||
@@ -257,7 +261,7 @@ function ListImpl<ItemT>(
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isInsideVisibleTree) {
|
if (!isInsideVisibleTree) {
|
||||||
// Prevents hidden tabs from firing scroll events.
|
// Prevents hidden tabs from firing scroll events.
|
||||||
// Only one list is expected to be firing these at a time.
|
// Only one list is expected to be firing these at a time.
|
||||||
@@ -395,7 +399,7 @@ function EdgeVisibility({
|
|||||||
containerRef: React.RefObject<Element | null>
|
containerRef: React.RefObject<Element | null>
|
||||||
onVisibleChange: (isVisible: boolean) => void
|
onVisibleChange: (isVisible: boolean) => void
|
||||||
}) {
|
}) {
|
||||||
const [containerHeight, setContainerHeight] = React.useState(0)
|
const [containerHeight, setContainerHeight] = useState(0)
|
||||||
useResizeObserver(containerRef, (w, h) => {
|
useResizeObserver(containerRef, (w, h) => {
|
||||||
setContainerHeight(h)
|
setContainerHeight(h)
|
||||||
})
|
})
|
||||||
@@ -416,7 +420,7 @@ function useResizeObserver(
|
|||||||
) {
|
) {
|
||||||
const handleResize = useNonReactiveCallback(onResize ?? (() => {}))
|
const handleResize = useNonReactiveCallback(onResize ?? (() => {}))
|
||||||
const isActive = !!onResize
|
const isActive = !!onResize
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -452,10 +456,10 @@ let Row = function RowImpl<ItemT>({
|
|||||||
extraData: any
|
extraData: any
|
||||||
onItemSeen: ((item: any) => void) | undefined
|
onItemSeen: ((item: any) => void) | undefined
|
||||||
}): React.ReactNode {
|
}): React.ReactNode {
|
||||||
const rowRef = React.useRef(null)
|
const rowRef = useRef(null)
|
||||||
const intersectionTimeout = React.useRef<
|
const intersectionTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(
|
||||||
ReturnType<typeof setTimeout> | undefined
|
undefined,
|
||||||
>(undefined)
|
)
|
||||||
|
|
||||||
const handleIntersection = useNonReactiveCallback(
|
const handleIntersection = useNonReactiveCallback(
|
||||||
(entries: IntersectionObserverEntry[]) => {
|
(entries: IntersectionObserverEntry[]) => {
|
||||||
@@ -468,12 +472,12 @@ let Row = function RowImpl<ItemT>({
|
|||||||
if (!intersectionTimeout.current) {
|
if (!intersectionTimeout.current) {
|
||||||
intersectionTimeout.current = setTimeout(() => {
|
intersectionTimeout.current = setTimeout(() => {
|
||||||
intersectionTimeout.current = undefined
|
intersectionTimeout.current = undefined
|
||||||
onItemSeen!(item)
|
onItemSeen(item)
|
||||||
}, ON_ITEM_SEEN_WAIT_DURATION)
|
}, ON_ITEM_SEEN_WAIT_DURATION)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (intersectionTimeout.current) {
|
if (intersectionTimeout.current) {
|
||||||
clearTimeout(intersectionTimeout.current as NodeJS.Timeout)
|
clearTimeout(intersectionTimeout.current)
|
||||||
intersectionTimeout.current = undefined
|
intersectionTimeout.current = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -482,7 +486,7 @@ let Row = function RowImpl<ItemT>({
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (!onItemSeen) {
|
if (!onItemSeen) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -490,10 +494,14 @@ let Row = function RowImpl<ItemT>({
|
|||||||
handleIntersection,
|
handleIntersection,
|
||||||
ON_ITEM_SEEN_INTERSECTION_OPTS,
|
ON_ITEM_SEEN_INTERSECTION_OPTS,
|
||||||
)
|
)
|
||||||
const row: Element | null = rowRef.current!
|
const row: Element | null = rowRef.current
|
||||||
observer.observe(row)
|
if (row) {
|
||||||
|
observer.observe(row)
|
||||||
|
}
|
||||||
return () => {
|
return () => {
|
||||||
observer.unobserve(row)
|
if (row) {
|
||||||
|
observer.unobserve(row)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [handleIntersection, onItemSeen])
|
}, [handleIntersection, onItemSeen])
|
||||||
|
|
||||||
@@ -507,7 +515,7 @@ let Row = function RowImpl<ItemT>({
|
|||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Row = React.memo(Row)
|
Row = memo(Row)
|
||||||
|
|
||||||
let Visibility = ({
|
let Visibility = ({
|
||||||
root,
|
root,
|
||||||
@@ -522,8 +530,8 @@ let Visibility = ({
|
|||||||
onVisibleChange: (isVisible: boolean) => void
|
onVisibleChange: (isVisible: boolean) => void
|
||||||
style?: ViewProps['style']
|
style?: ViewProps['style']
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const tailRef = React.useRef(null)
|
const tailRef = useRef(null)
|
||||||
const isIntersecting = React.useRef(false)
|
const isIntersecting = useRef(false)
|
||||||
|
|
||||||
const handleIntersection = useNonReactiveCallback(
|
const handleIntersection = useNonReactiveCallback(
|
||||||
(entries: IntersectionObserverEntry[]) => {
|
(entries: IntersectionObserverEntry[]) => {
|
||||||
@@ -538,15 +546,19 @@ let Visibility = ({
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
const observer = new IntersectionObserver(handleIntersection, {
|
const observer = new IntersectionObserver(handleIntersection, {
|
||||||
root: root?.current ?? null,
|
root: root?.current ?? null,
|
||||||
rootMargin: `${topMargin} 0px ${bottomMargin} 0px`,
|
rootMargin: `${topMargin} 0px ${bottomMargin} 0px`,
|
||||||
})
|
})
|
||||||
const tail: Element | null = tailRef.current!
|
const tail: Element | null = tailRef.current
|
||||||
observer.observe(tail)
|
if (tail) {
|
||||||
|
observer.observe(tail)
|
||||||
|
}
|
||||||
return () => {
|
return () => {
|
||||||
observer.unobserve(tail)
|
if (tail) {
|
||||||
|
observer.unobserve(tail)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [bottomMargin, handleIntersection, topMargin, root])
|
}, [bottomMargin, handleIntersection, topMargin, root])
|
||||||
|
|
||||||
@@ -554,9 +566,9 @@ let Visibility = ({
|
|||||||
<View ref={tailRef} style={addStyle(styles.visibilityDetector, style)} />
|
<View ref={tailRef} style={addStyle(styles.visibilityDetector, style)} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Visibility = React.memo(Visibility)
|
Visibility = memo(Visibility)
|
||||||
|
|
||||||
export const List = memo(React.forwardRef(ListImpl)) as <ItemT>(
|
export const List = memo(forwardRef(ListImpl)) as <ItemT>(
|
||||||
props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
|
props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
|
||||||
) => React.ReactElement<any>
|
) => React.ReactElement<any>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user