Search code examples
reactjsgraphqlfetchgraphene-django

How to write graphQL query from react using fetch api which support pagination?


Information:

  • I am using graphene-Django based backed
  • Using Relay Node-based query

Tasks that I can perform:

  • Write REST-based CRUD operations using fetch API in react.
  • Simple GraphQL queries that involve fetching a list or single item from the server.
  • Able to write GraphQL queries on GraphiQL

Want to do the following:

  • fetch a list of items from the server with pagination, that fetches say 10 items and the option to go to the first page, last page, Prev Page, and Next Page.
  • few examples would help

Solution

  • Solved by looking into various documentation, blogs, and my current requirement as:

    const Post = (props) => {
      const [isLoading, setLoading] = useState(true);
      const [posts, setPosts] = useState([])
      const [offset, setOffset] = useState(0)
      const [hasPrev, setHasPrev] = useState(false)
      const [hasNext, setHasNext] = useState(false)
      const pageSize = 10
    
      useEffect(() => {
        const loadData = () => {
          setLoading(true)
          const requestOptions = getGraphqlRequestOptions(pageSize, offset)
          fetch(graphql_url, requestOptions)
            .then(response => {
              setLoading(false)
              return response.json()
            })
            .then(data => {
              setHasNext(data.data.allPosts.pageInfo.hasNextPage)
              setPosts(data.data.allPosts.edges)
              setHasPrev(offset !== 0)
            })
        }
        loadData()
      }, [offset]);
    
      const handleNextClick = () => {
        setOffset(offset + pageSize)
      };
      const handlePrevClick = () => {
        setOffset(offset - pageSize)
      };
      useEffect(()=> {
        document.title = "MyTitle"
        setOffset(0)
      }, []);
    
      return (
        <>
          ... code to display table
          <div className="row mb-5">
            <Button 
              variant="outline-primary"
              className="col-1 me-auto"
              disabled={!(hasPrev || isLoading)}
              size="sm" block
              onClick={!isLoading ? handlePrevClick : null}
            >
              {isLoading ?  'Loading...' : 'Previous'}
            </Button>
            <Button 
              className="col-1 ms-auto"
              disabled={!(hasNext || isLoading)}
              onClick={!isLoading ? handleNextClick: null}
              variant="outline-primary" size="sm" block
            >
              {isLoading ?  'Loading...' : 'Next'}
            </Button>
          </div>
        </>
      }
    
    

    I was stuck because there were many options and no concrete example to implement this.
    For example:

    • We can use:
      1. query{allPosts(first:10, after:"last cursor"){pageInfo{hasPrevPage hasNextPage startCursor endCursor} edge{node{...}}}
      2. query{allPosts(first:10, offset:0){}} // currently used
      3. `query {allPosts(first:10, before:'start cursor'
      4. All above queries with last:10 instead of first:10, etc.
    • Beside this it returns a PageInfo object having hasNextPage, hasPrevPage, startCursor, endCursor.
      • It was giving informations that were hard to understand
      • Using query (1) i.e. with first and after option, hasPrevPage was always false
      • Using query(3) i.e. with before option, hasNextPage was always false
      • So need to track whether the Next and Prev page exists was difficult.