Quantcast
Channel: Active questions tagged react-native+typescript - Stack Overflow
Viewing all articles
Browse latest Browse all 6287

FlatList loads data multiple times

$
0
0

I have the next simple page:

type Props = {  getPostsUseCase: GetPostsUseCase}const renderItem = ({item}: ListRenderItemInfo<Post>) => (<NewsPost title={item.msg} />)const HomeScreen = ({getPostsUseCase}: Props) => {  const [isLoading, setLoading] = useState(true)  const [shouldFetch, setShouldFetch] = useState(true)  const [since, setSince] = useState<number | null>(null)  const [posts, setPosts] = useState<Post[]>([])  const fetchMore = useCallback(() => setShouldFetch(since != null), [since])  useEffect(() => {    // Prevent fetching for other state changes    if (!shouldFetch) return    getPostsUseCase      .execute({        limit: 15,        since: since,      })      .then((page: Page<Post>) => {        setPosts(oldPosts => [...oldPosts, ...page.data])        setSince(page.next)      })      .catch((error: string) => console.error(error))      .finally(() => {        setLoading(false)        setShouldFetch(false)      })  }, [getPostsUseCase, shouldFetch, since])  const onEndReachedCalledDuringMomentum = useRef(true)  const onEndReachedHandler = () => {    if (!onEndReachedCalledDuringMomentum.current) {      fetchMore()      onEndReachedCalledDuringMomentum.current = true    }  }  return (<SafeAreaView style={styles.frame}>      {isLoading ? (<Text>Loading...</Text>      ) : (<FlatList          style={styles.list}          data={posts}          renderItem={renderItem}          keyExtractor={item => item.id.toString()}          onEndReachedThreshold={0.1}          initialNumToRender={15}          onEndReached={onEndReachedHandler}          onMomentumScrollBegin={() => {            onEndReachedCalledDuringMomentum.current = false          }}        />      )}</SafeAreaView>  )}export default HomeScreen

However, it has two problems:

  1. It loads two pages on start (30 items, not 15, two requests to the backend)
  2. It loads entire collection multiple times on scrolling (there 30 items totally, it rendered 90)

Where is the problem? I found a lot of topics with similar problem, I tried their solutions but it didn't help (for example, this)

I am a noobie in React Native. To be honest, I don't even understand my problem and their solutions, and why they don't work.

UDP

Finally, I came up with a working solution but there is still an annoying moment:

type Props = {  getPostsUseCase: GetPostsUseCase}type Data = {  posts: Post[]  next: number | null}const renderItem = ({item}: ListRenderItemInfo<Post>) => (<NewsPost title={item.msg} />)const HomeScreen = ({getPostsUseCase}: Props) => {  const [isLoading, setLoading] = useState(true)  const [data, setData] = useState<Data>({    posts: [],    next: null,  })  const loadData = () => {    if (!isLoading && data.next == null) return    getPostsUseCase      .execute({        limit: 15,        since: data.next,      })      .then((page: Page<Post>) => {        setData(oldPage => ({          posts: [...oldPage.posts, ...page.data],          next: page.next,        }))      })      .catch((error: string) => console.error(error))      .finally(() => setLoading(false))  }  // eslint-disable-next-line react-hooks/exhaustive-deps  useEffect(loadData, [])  return (<SafeAreaView style={styles.frame}>      {isLoading ? (<Text>Loading...</Text>      ) : (<FlatList          style={styles.list}          data={data?.posts}          renderItem={renderItem}          keyExtractor={item => item.id.toString()}          onEndReachedThreshold={0.1}          onEndReached={loadData}        />      )}</SafeAreaView>  )}export default HomeScreen

ESlint requires to specify loadData in useEffect dependencies. I disabled that warning by // eslint-disable-next-line react-hooks/exhaustive-deps but it's a dirty trick...

How to fix the solution to I was not needed disabling an ESLint rule?


Viewing all articles
Browse latest Browse all 6287

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>