I have a case where I need something that is like a combination of the refetch and pagination containers. I want to paginate, but I also want to set search variables.
In Classic, the fragment container handled this fine. I am struggling with how to approach this. Any pointers?
This is a common question. We recommend a structure like this:
RefetchContainer: refetch when filter arguments change
PaginationContainer: paginate to load more for the same filter arguments
FragmentContainer: to render edges
i think this approach is similar with what my problem is, pull to refresh on RN flatlist with relay modern... https://github.com/facebook/relay/issues/1794 but i don't get it how to perform on such structure above, while on the example on the docs, refetch and pagination working on the same level of component
please enlighten me, maybe i lost something
I could make this work for myself. A key insight for me was that while a container might be further down the hierarchy, all the variables are global. Basically, the refresh/pagination container injects the refetch/reload helpers into the wrapped component, but all the query variables ($first, $search) are global and I can work with them at any point in the fragment hierarchy as I wish, including in parents.
One part that isn't pretty is that I have to repeat this full query three times, and any mistakes would only surface during runtime usage:
query ListRefetchQuery($search: String = "", $hasSearch: Boolean = false, $count: Int = 1, $cursor: String)
@miracle2k would you mind to share your full implementation RefetchContainer with PaginationContainer?
Thanks
That would be good.
this is my refetch and pagination
QueryRenderer
<QueryRenderer
environment={environment}
query={
graphql`
query search_taxQuery(
$count: Int,
$cursor: String,
$keyword: String
){
viewer{
...SearchTaxInput_viewer
}
}
`
}
variables={{
count: 30
}}
render={({error, props, retry}) => {
console.log('error', error);
if(props){
return(
<View style={{flex: 1, justifyContent: 'center'}}>
<SearchTaxInput {...props} />
</View>
);
}
return(
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator size="large" />
</View>
);
}}
/>
RefetchContainer
export default createRefetchContainer(
SearchTaxInput,
{
viewer: graphql.experimental`
fragment SearchTaxInput_viewer on viewer @argumentDefinitions(
keyword: {type: "String", defaultValue: ""},
count: {type: "Int", defaultValue: 30},
cursor: {type: "String", defaultValue: ""}
) {
...SearchTaxList_viewer
}
`
},
graphql.experimental`
query SearchTaxInputQuery(
$keyword: String,
$count: Int,
$cursor: String
){
viewer {
... SearchTaxInput_viewer @arguments(
keyword: $keyword,
first: $count,
after: $cursor
)
}
}
`
);
PaginationContainer
export default createPaginationContainer(
SearchTaxList,
{
viewer: graphql`
fragment SearchTaxList_viewer on viewer {
searchTaxClass(first: $count, after: $cursor, keyword: $keyword) @connection(key: "SearchTaxList_searchTaxClass"){
pageInfo{
hasNextPage
startCursor
endCursor
}
edges{
...SearchTaxItem_item
}
}
}
`
},
{
query: graphql`
query search_tax_listQuery(
$count: Int,
$cursor: String
$keyword: String
){
viewer {
...SearchTaxList_viewer
}
}
`,
getConnectionFromProps(props) {
return props.viewer.searchTaxClass;
},
direction: 'forward',
getFragmentVariables(prevVars, totalCount) {
return {
...prevVars,
count: totalCount
}
},
getVariables(props, { count, cursor }, fragmentVariables) {
return {
count,
cursor,
keyword: fragmentVariables.keyword
}
}
}
);
and lastly the fragmentContainer
export default createFragmentContainer(
SearchTaxItem,
graphql`
fragment SearchTaxItem_item on tax_classificationEdge{
cursor
node{
id
title
description
}
}
`
);
but there is still a defect, every time i call my refetch
let keyword = this.state.searchKey;
const refetchVariables = fragmentVariables => ({
keyword,
count: 30
});
this.props.relay.refetch(refetchVariables, null);
Thic code however still has a gotcha, and i'm still working on it
the queries does delivered to graphql server and processed it, but it doesn't update the paginated list, and also everytime i scroll to the bottom the keyword search query reset to null, which i'm still working on it
Im thinking the props seems undelivered to the child
Have the exact same problem @bondanherumurti, I can see my GraphQL query triggered by the RefetchContainer was successful in the network tab and it comes back with the correct results. But it's child PaginationContainer component is still rendering the edges from the initial static query.
You guys need to be running a custom fork patched with https://github.com/facebook/relay/pull/1702 to fix this problem, unfortunately.
thanks but I just npm linked to Rob's branch and I still get the same issue hmm
tried
"react-relay": "git+https://github.com/robrichard/relay.git#refetch-child-context"
doesnt work
I don't think you'll be able to reference the git uri, since the react-relay repo needs to be built (into multiple npm packages, actually). Not sur about npm link.
For my part, I have a fixed version of ReactRelayRefetchContainer.js that I copy into node_modules post every package install (when that change would be reset by npm). You can find it here:
https://gist.github.com/miracle2k/4ed8827d0ed1bd9419d4871c7e0492dc
thank you @miracle2k that is just work, however another question is, does this.props.relay.refetch, able to triggered this.props.relay.isLoading() on pagination list
it seems for me the refetch does work but it wont update the list nor the isLoading until i execute the this.props.relay.loadMore() on the paginationContainer... then it updates the list
So I discovered Rob's patch does partly fix my issue, when I load more pagination edges after the RefetchContainer has done a props.relay.refetch() with a props.relay.loadMore() in my PaginationContainer it then renders the initial items in the list with the items from the refetch.
So basically imagine my initial query renders [apples, oranges], I trigger a refetch and the GraphQL query returns [carrot, potato] but my view still renders [apples, oranges] (this is the bug). Then when I load more my GraphQL query returns [parsnip, sprouts] and the view renders [carrot, potato, parsnip, sprouts].
If anyone has any ideas why this is happening that would be awesome. I'll try make a reproducible example when I have time.
@bondanherumurti in your example , if you remove refetch container from the hierarchy , and then assign the new keyword to your query renderer's variables, will that work?
according to source code
QueryRenderer will do a refetch after you update its variables. so effectively, it can do what a refetch-container can do; also, it can be nested in other containers; it's a very powerful component
@bochen2014 that is exactly what i did, to make the search list working
cool. that's what I thought. thanks for letting me know
is there any functionality in paginationContainer that allow the list to be refreshed? just incase i put "refresh list button" or "pull to refresh the list"?
I've recently migrated a very large app to relay modern and found-relay from relay classic and react-router-relay. The migration has been surprisingly smooth with one exception: I haven't been able to get Refetch and Pagination containers to work with one another.
Just like @bondanherumurti I have a Fragment Container (ProductItem) nested inside a Pagination Container (ProductList) nested inside a Refetch Container (ProductCatalog). The Pagination container is used for the infinite scrolling of products. The Refetch container is used for Filtering products by price/type/ etc...
Pagination works perfectly. Filtering, for most use cases, does not. For ex. when I call this.props.relay.refetch({ category: 'red-wine'}), only red wines should show. But nothing happens. In relay classic, doing this was as simple as calling this.props.relay.setVariables({ category: 'red-wine'}).
I can see via network requests that the correct result is indeed being returned from GraphQL ( so it appears that refetch functionality is working ) but the pagination container does not update with the correct result.
Strangely, when I do this.props.relay.refetch({ count: 2}) the pagination container updates as expected, only showing two products. But if I do this.props.relay.refetch({ count: 2, category: 'red-wine'}) nothing happens. Again, GraphQL returns the correct result.
I would have assumed this was an issue on my end except that I stumbled upon this thread where several others are running into this exact issue too.
I'm not sure how to implement the fix to the QueryRenderer as some have suggested above as I'm using found-relay for routing.
Any help/insights would be much appreciated. Just need to figure out this issue and my conversion to relay modern will be complete :)
To see a visual of what I'm talking about, you can view the Relay Classic version of my app here. https://beta.onehopewine.com/shop/wine/wine
@miracle2k : after copied your fix into ReactRelayRefetchContainer.js, my app is broken. I guest it is still not compatible with new version.
my packages: [email protected], [email protected], [email protected]
is there any example of pagination using only refetchcontainer?
I've managed to implementation pagination using only refetch container
follow this issue https://github.com/facebook/relay/issues/1972 to do it
Is there any update on this? I'm currently running into this issue as well. Don't mind helping out if https://github.com/facebook/relay/pull/1702 or a new PR is the solution. I would rather not keep my searching and pagination logic in the same refetch container.
With 6bc91271f31e5e268784be516ed6c3190d82c89f, you don't have to use a refetch container anymore. Pagination container should let you refetch variables as well
You'd do this through a third argument passed to the refetchConnection method which lets you set new variables on a refetch (It sorta works like setState in react: only the keys you set in the object passed in will overwrite old variables)
Thanks for the info @pranaygp. Am I correct that this feature is only available in modern and not compat?
edit: disregard. I upgraded react-relay from 1.1.0 to 1.2.0 and it's working now with relay-compat.
I think paginationContainer is not working properly on compat mode
@pranaygp can you take a look?
the problem is that loadMore is not taking into account refetchVariables on loadMore
The refetchVariables get cached into this._relayContext. when calling loadMore, we use the cached variables (but overwrite count and cursor with new values) before making the request. loadMore doesn't have to explicitly make use of refetchVariables. Are you sure this is an error in compat mode only? Can you also give this a shot in 1.3.0?
I'm using 1.3.0 and I also tested on master version
both are not working properly
I think it is related to local variables defined using @argumentDefinitions without a defaultValue
I'm having the same issue, the refetch query runs okay and the response will come back from the server, but the ui doesn't get updated. or to be more precise the props of the refetch container don't get updated.
Here is my relay decorator:
@compose(
queryRenderer(graphql`
query UsersQuery($page: Int, $count: Int) {
users(page: $page, count: $count) {
...Users_users
}
}
`, {
page: 1,
count: 25
}),
refetchContainer(
graphql`
fragment Users_users on UserPaginationResult {
data {
...UserRow_user
}
pageInfo {
totalCount
pagesCount
}
}
`,
graphql`
query UsersRefetchQuery($page: Int!,$count: Int!) {
users(page: $page, count: $count) {
...Users_users
}
}
`
)
)
And here is my refetch function:
loadMore(page) {
const { count } = this.state;
const { relay: { refetch } } = this.props;
refetch({ page, count });
}
This seems super broken still? loadMore always overrides any refetchVariables with their default value, making refetchConnection useless with pagination, since the moment you call loadMore whatever you fetched is ignored.
@jquense Can you open a new issue with details on how it鈥檚 broken?
There is already a few issues open https://github.com/facebook/relay/issues/1986
The issue seems covered in a few places ? There is even a PR to address it. I can open up a new one but the problem seems to be one of prioritization not knowledge yeah? Happy to open a new one if that is helpful
Nope, no need for dupes, just want to make sure all current issues are indeed covered by their own open tickets.
By the PR, are you referring to the one that鈥檚 mentioned on #1986, namely #1868? Because that one is too out-of-date currently and won鈥檛 apply easily :/
Is there a reason these bugs aren't priorities for the core team? I know ya'll busy, it's a bit disheartening tho, to try and migrate to relay modern and hit a few game stopping bugs (I may just be unlucky) almost immediately: #1740 #1986 and #2193 many I think all of which have had PR's for months (super glad the flow one finally got in). When we see PR's that seem otherwise good (?) get stale do to lack of attention that reads like a lack of interest in the problem. That's of course fine ya'll have your jobs to do. It'd be helpful to know what those priorities are for OSS users, since it doesn't seem like contributing is often a viable way to get bugs addressed quickly.
I hope the above doesn't come off as a criticism or complaint, i'm just trying to get a handle on what the direction and tone of the project is for our own set of responsibilities! Thanks again for all the hard work! cc @taion
My _observation_ is that the Relay team鈥檚 priorities are issues that apply to internal FB needs and the same applies to other companies relying on Relay, meaning that filing an issue that does not apply to FB or one of the other companies will not be prioritised and so PRs are a faster way to getting fixes in for your issue.
However, getting outside contributions into the mainline requires spare time of one of the team鈥檚 members to review and ensure they don鈥檛 negatively affect FB鈥檚 needs, because that spare time is rare I try to help them to not have to review issues/PRs that aren鈥檛 reviewable yet (note that I鈥檓 not an FB employee).
Having said that, we (Artsy) build our own Relay packages from a branch where we cherry-pick the PRs that have not been merged yet and apply to us: https://github.com/alloy/relay/releases. So it doesn鈥檛 have to be a hard blocker, but it鈥檚 definitely a time investment.
Ah sorry you're from Artsy! Not paying enough attention. good to know tho, we've been wondering how ya'll handle this as well being a big Relay user. Maybe are team and yours could chat a bit more about it sometime :)
Sure thing! Let鈥檚 take that elsewhere, though, maybe ping me on http://graphql.slack.com/channels/relay ? (You can sign-up here http://graphql-slack.herokuapp.com)
Hey @jquense just wanted to chime in regarding this specific issue (paginating + refetch). We're working on an internal fix for that issue.
I believe so yes. Thanks!
thanks! I'll keep you posted when we land the fix
josephsavona (second) post is answer to how to implement pagination + filtering.
you can do pagination using refetchContainer like this https://medium.com/entria/relay-modern-pagination-using-refetch-container-editing-a07c6b33ae4e
fyi #1986 has been fixed in the latest release
Most helpful comment
This is a common question. We recommend a structure like this: