Last active
April 25, 2023 14:57
-
-
Save BenQoder/ce1e9cd3fc882ccd7ad82276bf22ef36 to your computer and use it in GitHub Desktop.
Implementing Infinite Scroll With Redux Toolkit Query
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { createApi } from "@reduxjs/toolkit/query/react"; | |
| import { createEntityAdapter } from "@reduxjs/toolkit"; | |
| // Create Adapter For Posts To Avoid Duplicates | |
| const postsAdapter = createEntityAdapter({ | |
| selectId: (post) => post.id, | |
| sortComparer: (a, b) => b.createdAt - a.createdAt, | |
| }); | |
| const postsApi = createApi({ | |
| reducerPath: "posts", | |
| endpoints: (build) => ({ | |
| fetchPosts: build.query({ | |
| keepUnusedDataFor: 600 // Keep unused for longer, | |
| query: (page) => { | |
| return `posts?page=${page}`; | |
| }, | |
| transformResponse: (response) => { | |
| // Return Post To State Using Adapters | |
| return postsAdapter.addMany( | |
| postsAdapter.getInitialState({ | |
| hasMorePages: response.hasMorePages, | |
| }), | |
| response.data | |
| ); | |
| }, | |
| async onQueryStarted(page, { queryFulfilled, dispatch }) { | |
| if (!page) { | |
| return; | |
| } | |
| const { data } = await queryFulfilled; | |
| if (data) { | |
| // Add Posts On Current Request To Page 1 | |
| dispatch( | |
| postsApi.util.updateQueryData( | |
| "fetchPosts", | |
| 1, | |
| (draft) => { | |
| postsAdapter.addMany( | |
| draft, | |
| postsSelector.selectAll(data) | |
| ); | |
| draft.hasMorePages; | |
| } | |
| ) | |
| ); | |
| if (page > 1) { | |
| // Remove Cached Data From State Since We Already Added It To Page 1 | |
| dispatch( | |
| postsApi.util.updateQueryData( | |
| "fetchPosts", | |
| page, | |
| (draft) => { | |
| draft = postsAdapter.getInitialState(); | |
| } | |
| ) | |
| ); | |
| } | |
| } | |
| }, | |
| }), | |
| }), | |
| }); | |
| export const { | |
| postsApi | |
| } = postsApi; | |
| export default postsApi; | |
| const postsSelectors = postsAdapter.getSelectors((state) => state); | |
| export { postsSelectors, postsAdapter }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { View, FlatList } from "react-native"; | |
| import React, { useEffect, useRef } from "react"; | |
| import postsApi, { | |
| postsAdapters, | |
| postsSelectors, | |
| useLazyFetchPostsQuery | |
| } from "../../state/apis/postsApi"; | |
| export default function PostsScreen() { | |
| const currentPage = useRef(1); | |
| const [fetchPosts, { isFetching }] = | |
| useLazyFetchPostsQuery(); | |
| // Listen For Posts Updates Page 1 | |
| const { posts, hasMorePages } = | |
| postsApi.endpoints.fetchPosts.useQueryState(1, { | |
| selectFromResult: (result) => { | |
| return { | |
| hasMorePages: result.data?.hasMorePages, | |
| posts: postsSelectors.selectAll( | |
| result.data ?? postsAdapters.getInitialState() | |
| ), | |
| }; | |
| }, | |
| }); | |
| const fetchFirstPage = async () => { | |
| await fetchPosts(currentPage.current); | |
| }; | |
| const fetchMorePosts = async () => { | |
| if(!hasMorePages || isFetching) return; | |
| currentPage.current += 1; | |
| await fetchPosts(currentPage.current); | |
| }; | |
| useEffect(() => { | |
| // Fetch First Page On Init | |
| fetchFirstPage() | |
| },{}) | |
| return ( | |
| <FlatList | |
| data={posts} | |
| renderItem={....} | |
| onEndReached={fetchMorePosts} | |
| /> | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment