Closed stan-sack closed 6 years ago
try to do pagination using refetchContainer, check this guide https://github.com/entria/guidelines/blob/master/relay/flatlist-relaymodern.md#onendreached-relay-modern-createrefetchcontainer
@sibelius I followed your guidelines but still no luck. I think it's because I don't pass the arguments down correctly and because of this when I try to paginate after refetching, the new cursor
and field
params are not propagated.
I am getting the error GraphQLParser: Unknown directive @argumentDefinitions.
when I try to compile the code. Do you know how I can fix this error? How do you disable the compiler check for this? I see a lot of people using these directives but cant find any documentation about how to enable them.
use relay 1.5.0 or the latest version to have @argumentDefinitions
read more about it here https://medium.com/entria/relay-modern-argumentdefinitions-d53769dbb95d
more about how connection are handled in relay:
all connections need @connection, this is how relay can find the connection.
@connection has to params:
so for you example
it will create a new connection based on different values of your connection args
countryName: $countryName
state: $state
filter: $filter
you should use filters: []
to create only one connection
I think on paginationContainer you need to use getVariables
and pass with args are you using to select the correct connection to read data from.
that's what we do with renderVariables
on refetchContainer
Yes I understand. I've read all of your blogs - they are basically the only in depth resource on relay modern. I am actually using the your ReactNavigationRelayModern boilerplate :).
I am on relay 1.6 which is why I am confused that I am getting this error.
My package.json
looks like this:
"dependencies": {
"lodash": "^4.17.10",
"react": "^16.0.0",
"react-native": "^0.55.4",
"react-native-datepicker": "^1.7.2",
"react-native-easy-toast": "^1.1.0",
"react-native-elements": "^0.19.1",
"react-native-facebook-login": "^1.6.1",
"react-native-google-places-autocomplete": "^1.3.6",
"react-native-modal-filter-picker": "^1.3.4",
"react-native-modal-selector": "0.0.27",
"react-native-permissions": "^1.1.1",
"react-native-radio-buttons": "^1.0.0",
"react-native-sensitive-info": "git://github.com/mcodex/react-native-sensitive-info.git#keystore",
"react-native-splash-screen": "^3.0.6",
"react-native-svg": "^6.3.1",
"react-native-vector-icons": "^4.6.0",
"react-navigation": "^2.0.1",
"react-relay": "^1.6.0",
"victory-native": "^0.17.4"
},
"devDependencies": {
"@babel/core": "^7.0.0-beta.47",
"babel-eslint": "^8.2.3",
"babel-jest": "22.4.3",
"babel-plugin-relay": "^1.6.0",
"babel-polyfill": "^6.26.0",
"babel-preset-react-native": "4.0.0",
"babel-preset-react-native-stage-0": "^1.0.1",
"eslint": "^4.19.1",
"eslint-config-prettier": "^2.9.0",
"eslint-config-standard": "^12.0.0-alpha.0",
"eslint-config-standard-react": "^6.0.0",
"eslint-plugin-babel": "^5.1.0",
"eslint-plugin-flowtype": "^2.46.3",
"eslint-plugin-import": "^2.11.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-prettier": "^2.6.0",
"eslint-plugin-promise": "^3.7.0",
"eslint-plugin-react": "^7.8.2",
"eslint-plugin-react-native": "^3.2.1",
"eslint-plugin-standard": "^3.1.0",
"graphql": "^0.13.2",
"hoist-non-react-statics": "^2.5.0",
"jest": "22.4.3",
"lint-staged": "^7.1.0",
"prettier": "^1.12.1",
"prettier-eslint": "^8.8.1",
"react-devtools": "^3.2.3",
"react-test-renderer": "16.3.2",
"relay-compiler": "^1.6.0",
"relay-devtools": "^1.4.0"
}
try to use relay 1.5.0 on react-native
relay 1.6.0 requires react 16.3.0
if you use an older react version it causes some bugs
I got it working. For anyone reading this in future the working component looks like this:
import React from 'react'
import { View, TextInput, Text, TouchableOpacity } from 'react-native'
import { FormLabel, FormValidationMessage } from 'react-native-elements'
import { createPaginationContainer, graphql, QueryRenderer } from 'react-relay'
import ModalFilterPicker from '../../components/ModalFilterPicker'
import { withNavigation } from 'react-navigation'
import environment from '../../createRelayEnvironment'
import hoistStatics from 'hoist-non-react-statics'
@withNavigation
class AgencySelector extends React.Component {
constructor(props, ctx) {
super(props, ctx)
this.state = {
modalVisible: false,
filter: null,
refreshing: false,
}
}
_loadMore() {
if (!this.props.relay.hasMore() || this.props.relay.isLoading()) {
return
}
this.setState({ refreshing: true })
this.props.relay.loadMore(
10, // Fetch the next 10 feed items
() => {
this.setState({ refreshing: false })
}
)
}
_updateText(text) {
this.setState({ filter: text })
this._refetch()
}
_refetch() {
if (this.props.relay.isLoading() || !this.state.filter) {
return
}
this.setState({ refreshing: true })
this.props.relay.refetchConnection(
30,
() => {
this.setState({ refreshing: false })
},
{
filter: {
field: 'name',
value: this.state.filter,
},
count: 30,
countryName: this.props.countryName,
state: this.props.state,
}
)
}
render() {
let agencies = this.props.agencies.findAgencies.edges.map((edge, i) => {
return {
label: edge.node.name,
key: i,
}
})
return (
<View>
<FormLabel>Agency</FormLabel>
<TouchableOpacity
onPress={() => this.setState({ modalVisible: true })}>
<TextInput
style={{
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
height: 40,
}}
editable={false}
placeholder="Name of the agency"
value={this.props.parentProps.value}
pointerEvents="none"
/>
</TouchableOpacity>
<ModalFilterPicker
onFilterTextChanged={text => this._updateText(text)}
options={agencies}
visible={this.state.modalVisible}
onSelect={option =>
this.props.parentProps.onOptionSelected(option.label)
}
onCancel={() => this.setState({ modalVisible: false })}
flatListViewProps={{
onEndReached: () => this._loadMore(),
onEndReachedThreshold: 3,
}}
/>
{this.props.error &&
this.props.parentProps.showError && (
<FormValidationMessage>
this.props.parentProps.error
</FormValidationMessage>
)}
</View>
)
}
}
const AgenciesPaginationContainer = createPaginationContainer(
AgencySelector,
graphql`
fragment AgencySelector_agencies on Query {
findAgencies(
after: $after
first: $count
filter: $filter
countryName: $countryName
state: $state
) @connection(key: "AgencySelector_findAgencies") {
edges {
node {
name
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`,
{
direction: 'forward',
query: graphql`
query AgencySelectorPaginationQuery(
$after: String
$count: Int
$countryName: String
$state: String
$filter: FilterInput
) {
...AgencySelector_agencies
}
`,
getConnectionFromProps(props) {
return props.agencies && props.agencies.findAgencies
},
getFragmentVariables(previousVariables, totalCount) {
return {
...previousVariables,
count: totalCount,
}
},
getVariables(props, { count, cursor }, fragmentVariables) {
return {
after: cursor,
count: count,
countryName: fragmentVariables.countryName,
state: fragmentVariables.state,
filter: fragmentVariables.filter,
}
},
}
)
const rootQuery = graphql`
query AgencySelectorQuery(
$count: Int
$after: String
$countryName: String
$state: String
$filter: FilterInput
) {
...AgencySelector_agencies
}
`
const AgencySelectorQueryRenderer = props => {
let parentProps = props
return (
<QueryRenderer
environment={environment}
query={rootQuery}
variables={{
count: 30,
after: null,
countryName: props.countryName,
state: props.state,
filter: {
field: '',
value: '',
},
}}
render={({ error, props }) => {
if (props) {
return (
<AgenciesPaginationContainer
agencies={props}
parentProps={parentProps}
/>
)
} else {
return <Text>Loading</Text>
}
}}
/>
)
}
export default hoistStatics(AgencySelectorQueryRenderer, AgencySelector)
Thanks for your help @sibelius.
I just came across a similar problem with the PaginationContainer
. I've upgraded from 1.6.1 to 1.6.2 and my pagination stopped working. Finally, after some painful debugging and got to this post and as mentioned in https://github.com/facebook/relay/issues/2468#issuecomment-397610337 I added filters: []
to my connection directive.
@connection(key: "PeoplePaginationContainer_people", filters: [])
Now my component is back to live again.
Anyway, according to the docs, filters
is optional, however, I believe that if you have to provide the empty array, then it is actually not optional.
filters tell Relay if you want to create a different connection for each different arguments of the connection
Usually you only need one connection, so using filters:[] works fine.
However, if you have multiple components that is using this connection with different arguments, you should provide filters to make this work
I have a couple or maybe 3 components using the same pagination container. It worked fine without the filters in 1.6.1, and it stopped working for components using the pagination container with $search
arg in 1.6.2.
It wasn't easy to find out what was wrong because there was no error in the js console, but anyway, I hope google can point to this thread if other folks run into similar problem.
Hey I've been trying to fetch next data using pagination container and refetching connection and i do not receive new data. Request to my graphql severe is made but it still fetches the data from given offset. How I am i suppose to fetch new data? Also I am using relay modern.
It sounds like your variables aren't setup correctly. In particular after
. It's hard to say for sure without a snippet.
I have a couple or maybe 3 components using the same pagination container. It worked fine without the filters in 1.6.1, and it stopped working for components using the pagination container with
$search
arg in 1.6.2.It wasn't easy to find out what was wrong because there was no error in the js console, but anyway, I hope google can point to this thread if other folks run into similar problem.
Wow. Thanks! I was also using $search
and could not for the life of me understand the difference between a failing pagination case and my working ones. Until I found your post!
Initially my component paginates fine. I am able to update my filter and call
relay.refetchConnection
which returns the new connection and as well as a new cursor which I can see from logging the props ingetConnectionFromProps
.My issue is that once i try to scroll my list and
relay.loadMore
is called to get the next page of the new filtered list, the cursor and query never update. I can see the request on my server asking for the next page which I believe executes correctly but relay never loads the new data and every subsequent call toloadMore
sends the same request. I think thatloadMore
is not updating the internal state correctly afterrefetchConnection
is called.My component is as shown below: