Address lint warnings in List.web.tsx (#10046)

This commit is contained in:
DS Boyce
2026-03-13 09:41:38 -07:00
committed by GitHub
parent 97fdd7c59b
commit b8d60eb0e2
+45 -33
View File
@@ -1,9 +1,13 @@
import React, {
import {
forwardRef,
isValidElement,
type JSX,
memo,
startTransition,
useCallback,
useEffect,
useImperativeHandle,
useRef,
useState,
} from 'react'
import {
type FlatListProps,
@@ -39,7 +43,7 @@ export type ListProps<ItemT> = Omit<
*/
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_INTERSECTION_OPTS = {
@@ -77,7 +81,7 @@ function ListImpl<ItemT>(
const isEmpty = !data || data.length === 0
let headerComponent: JSX.Element | null = null
let headerComponent: React.JSX.Element | null = null
if (ListHeaderComponent != null) {
if (isValidElement(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 (isValidElement(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 (isValidElement(ListEmptyComponent)) {
emptyComponent = ListEmptyComponent
@@ -113,9 +117,9 @@ function ListImpl<ItemT>(
})
}
const getScrollableNode = React.useCallback(() => {
const getScrollableNode = useCallback(() => {
if (disableFullWindowScroll) {
const element = nativeRef.current as HTMLDivElement | null
const element = nativeRef.current
if (!element) return
return {
@@ -186,8 +190,8 @@ function ListImpl<ItemT>(
}
}, [disableFullWindowScroll])
const nativeRef = React.useRef<HTMLDivElement>(null)
React.useImperativeHandle(
const nativeRef = useRef<HTMLDivElement>(null)
useImperativeHandle(
ref,
() =>
({
@@ -226,7 +230,7 @@ function ListImpl<ItemT>(
useResizeObserver(containerRef, onContentSizeChange)
// --- onScroll ---
const [isInsideVisibleTree, setIsInsideVisibleTree] = React.useState(false)
const [isInsideVisibleTree, setIsInsideVisibleTree] = useState(false)
const handleScroll = useNonReactiveCallback(() => {
if (!isInsideVisibleTree) return
@@ -257,7 +261,7 @@ function ListImpl<ItemT>(
)
})
React.useEffect(() => {
useEffect(() => {
if (!isInsideVisibleTree) {
// Prevents hidden tabs from firing scroll events.
// Only one list is expected to be firing these at a time.
@@ -395,7 +399,7 @@ function EdgeVisibility({
containerRef: React.RefObject<Element | null>
onVisibleChange: (isVisible: boolean) => void
}) {
const [containerHeight, setContainerHeight] = React.useState(0)
const [containerHeight, setContainerHeight] = useState(0)
useResizeObserver(containerRef, (w, h) => {
setContainerHeight(h)
})
@@ -416,7 +420,7 @@ function useResizeObserver(
) {
const handleResize = useNonReactiveCallback(onResize ?? (() => {}))
const isActive = !!onResize
React.useEffect(() => {
useEffect(() => {
if (!isActive) {
return
}
@@ -452,10 +456,10 @@ let Row = function RowImpl<ItemT>({
extraData: any
onItemSeen: ((item: any) => void) | undefined
}): React.ReactNode {
const rowRef = React.useRef(null)
const intersectionTimeout = React.useRef<
ReturnType<typeof setTimeout> | undefined
>(undefined)
const rowRef = useRef(null)
const intersectionTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(
undefined,
)
const handleIntersection = useNonReactiveCallback(
(entries: IntersectionObserverEntry[]) => {
@@ -468,12 +472,12 @@ let Row = function RowImpl<ItemT>({
if (!intersectionTimeout.current) {
intersectionTimeout.current = setTimeout(() => {
intersectionTimeout.current = undefined
onItemSeen!(item)
onItemSeen(item)
}, ON_ITEM_SEEN_WAIT_DURATION)
}
} else {
if (intersectionTimeout.current) {
clearTimeout(intersectionTimeout.current as NodeJS.Timeout)
clearTimeout(intersectionTimeout.current)
intersectionTimeout.current = undefined
}
}
@@ -482,7 +486,7 @@ let Row = function RowImpl<ItemT>({
},
)
React.useEffect(() => {
useEffect(() => {
if (!onItemSeen) {
return
}
@@ -490,10 +494,14 @@ let Row = function RowImpl<ItemT>({
handleIntersection,
ON_ITEM_SEEN_INTERSECTION_OPTS,
)
const row: Element | null = rowRef.current!
observer.observe(row)
const row: Element | null = rowRef.current
if (row) {
observer.observe(row)
}
return () => {
observer.unobserve(row)
if (row) {
observer.unobserve(row)
}
}
}, [handleIntersection, onItemSeen])
@@ -507,7 +515,7 @@ let Row = function RowImpl<ItemT>({
</View>
)
}
Row = React.memo(Row)
Row = memo(Row)
let Visibility = ({
root,
@@ -522,8 +530,8 @@ let Visibility = ({
onVisibleChange: (isVisible: boolean) => void
style?: ViewProps['style']
}): React.ReactNode => {
const tailRef = React.useRef(null)
const isIntersecting = React.useRef(false)
const tailRef = useRef(null)
const isIntersecting = useRef(false)
const handleIntersection = useNonReactiveCallback(
(entries: IntersectionObserverEntry[]) => {
@@ -538,15 +546,19 @@ let Visibility = ({
},
)
React.useEffect(() => {
useEffect(() => {
const observer = new IntersectionObserver(handleIntersection, {
root: root?.current ?? null,
rootMargin: `${topMargin} 0px ${bottomMargin} 0px`,
})
const tail: Element | null = tailRef.current!
observer.observe(tail)
const tail: Element | null = tailRef.current
if (tail) {
observer.observe(tail)
}
return () => {
observer.unobserve(tail)
if (tail) {
observer.unobserve(tail)
}
}
}, [bottomMargin, handleIntersection, topMargin, root])
@@ -554,9 +566,9 @@ let Visibility = ({
<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>},
) => React.ReactElement<any>