ra-aws-amplify icon indicating copy to clipboard operation
ra-aws-amplify copied to clipboard

Get nextToken working with GET_LIST API call, pagination

Open mayteio opened this issue 4 years ago • 6 comments

Currently the infrastructure is in place, though the pagination doesn't actually work - just refetches the first 10.

Now nextToken is stored in redux, it needs to be pulled out in buildVariablesImp and included in the final variables that get sent to GraphQL.

mayteio avatar Mar 18 '20 07:03 mayteio

Struggling with this. When I pass the nextToken in as a filter and use it in a query, I get an infinite loop that goes from page 1 -> 2 -> 1 -> 2 etc.

mayteio avatar Mar 24 '20 01:03 mayteio

Hey, @mayteio great project! It's helping our team scaffold out our project quickly but we are really stuck on this one. Can you help point to where we can look into this one and help? Or is this more of a problem with RA working in with Amplify graphql?

senorgeno avatar Apr 28 '20 21:04 senorgeno

👋 hey @senorgeno, glad you've found it helpful so far. I'd be happy to point you in the right direction.

Firstly, there's a reducer that catches the nextToken and stores it in redux. You can use it like so:

import { nextTokenReducer } from 'ra-aws-amplify';

export const App = () => (
  <Admin ... customReducers={{ nextToken: nextTokenReducer }} />
)

Note: In future release I'd like the API to be import {reducers} from 'ra-aws-amplify' as while working on many-to-many relationships there are additional reducers we need to pass in, just FYI.


Then, in your list page we have an Amplify Pagination component we can pass in for next/prev instead of having numbers (as DynamoDB doesn't support total records out of the box).

Here's where I'm stuck: I wanted to use permanent filters to pass the nextToken to the dataProvider. Permanent filters were the only way to pass arbitrary variables through to the dataProvider from my research.

import { AmplifyPagination } from 'ra-aws-amplify'

export const PostList = props => {
  const nextToken = useSelector(state => state.nextToken);
  return <List {...props} pagination={<AmplifyPagination />} filter={{nextToken}} />
}

Note: the use selector could be abstracted into a hook like useNextToken() so there's minimal cognitive overhead and can be re-used in the <AmplifyPagination /> component.


Problem is, when you actually pass the nextToken to the API call I am getting a loop that constantly goes from page 1 -> 2 -> 1 -> 2 -> 1 -> etc. Uncomment here:

https://github.com/mayteio/ra-aws-amplify/blob/112dd87fc2b2187266deb01b2b1b73e13ee1e6d0/src/buildAmplifyProvider/buildVariables.ts#L136-L140

The buildGetListVariables is responsible for building the filter that gets passed to the Amplify GraphQL listPosts query, for example:

query ListPosts(
    $filter: ModelPostFilterInput
    $limit: Int
    $nextToken: String
  ) {
    listPosts(filter: $filter, limit: $limit, nextToken: $nextToken) {
      id
      ...
    }
}

https://github.com/mayteio/ra-aws-amplify/blob/112dd87fc2b2187266deb01b2b1b73e13ee1e6d0/src/buildAmplifyProvider/buildQuery.ts#L36-L41

I don't have time to look at it this week but I am 100% open to collaborating here if you manage to fix it and want to submit a PR for it!

Let me know if I can help or if you have any questions.

mayteio avatar Apr 28 '20 22:04 mayteio

import { AmplifyPagination } from 'ra-aws-amplify'

export const PostList = props => {
  const nextToken = useSelector(state => state.nextToken);
  return <List {...props} pagination={<AmplifyPagination />} filter={{nextToken}} />
}

The nextToken shouldn't be inserted into the filter directly because then the list will try to reload immediately.

What is desired is to insert nextToken when the "Next" link is clicked within the pagination component.

ericluwj avatar Sep 24 '20 10:09 ericluwj

Unreal, thanks for the info. Have you fixed this in a PR or should I jump in and do it?

mayteio avatar Sep 24 '20 10:09 mayteio

I'm using a quick workaround by doing this:

import { AmplifyPagination } from 'ra-aws-amplify'

export const PostList = props => {
  const [nextToken, setNextToken] = useState(null);
  return <List {...props} pagination={<AmplifyPagination onNext={(nextToken) => setNextToken(nextToken)} />} filter={{nextToken}} />
}

I also overrided AmplifyPagination to support onNext. But it might just be better to create a custom list for Amplify support.

And I think there's also a lot more to be done in ra-aws-amplify/src/buildAmplifyProvider/buildVariables.ts, to also support number of records per page and filters. So ideally it would be best for you to continue with it.

ericluwj avatar Sep 25 '20 01:09 ericluwj