Refetching works fine with pagintationContainer but with refetchContainer the new props never get updated even though the response comes back from the server correctly as shown in the network tab. I can't figure this out.
Can you put up some code which we could try to help you debug.
It seems very strange, since everything in that stackoverflow issue looks fine.
Oh I think I got through a similar problem too. If I remember correctly I believe the "id" Relay is using to identify the component is including the variables for the initial query so try unwrapping your container fragment in the QueryRenderer by moving the searchUsers(..) to the fragment and then in the query just ...Search_user. You'll have to define Search_user as a fragment of your root, i.e.: in my case it'd something like fragment Search_user on RootQueryType. My last suggestion is turning your debugger on and see whats going on when you get the data.
This seems to be a bug. Moving the query to the fragment works...
Working code:
ReactDOM.render((
<QueryRenderer
environment={environment}
query={graphql`
query appQuery($songId: Int) {
...editSongModalContainer
}
`}
variables={{
songId: 104,
}}
render={({error, props}) => {
if (error) {
return <div>{error.message}</div>;
} else if (props) {
return <EditSongModal data={props} />;
}
return <div>Loading</div>;
}}
/>
), document.getElementById('app'));
class TodoItem extends React.Component {
render() {debugger
const item = this.props.data.song;
return (
<div>
{item.name}
<button onClick={this._refetch} title="Refresh">refresh</button>
</div>
);
}
_refetch = () => {
this.props.relay.refetch(
{songId: 105}, // Our refetchQuery needs to know the `itemID`
null, // We can use the refetchVariables as renderVariables
() => { console.log('Refetch done') },
{force: true}, // Assuming we've configured a network layer cache, we want to ensure we fetch the latest data.
);
}
}
export default createRefetchContainer(
TodoItem,
graphql`
fragment editSongModalContainer on Query {
song(id: $songId) {
name
coverImageUrl
artist
}
}
`,
graphql`
query editSongModalContainerRefetchQuery(
$songId: Int
) {
...editSongModalContainer
}
`
);
Hey @MartinDawson, sorry for the delay in getting back to you on this issue!
This is actually expected behavior, and I'll try to expand on the answer from stack overflow. When refetch is called and the refetchQuery is executed, Relay doesn't actually use the result of the query to re-render the component. All it does is normalize the payload into the store and fire any relevant subscriptions. This means that if the fetched data is unrelated to the data that the mounted container is subscribed to (e.g. using a totally different node id that doesn't have any data overlaps), then the component won't re-render.
In this specific scenario, the reason why the container doesn't re-render, i.e. why it isn't subscribed to the changes fired by the refetchQuery, is due to how subscriptions are set up. A subscription is basically a subscription to a snapshot, which basically represents a concrete fragment and the data and records associated with it at a given point in time -- when the records associated with a snapshot change, the subscription for that snapshot will be notified of changes.
In this case, given that the fragment for the container has no variables, the snapshot that it will subscribe to will only be associated with the initial node; after refetch happens and the the store is updated, the records for the new node will have been updated, but the record associated with that original snapshot hasn't changed, so the container subscribed to it won't be notified.
This means that Refetch containers are only really meant to be used when you are changing variables in the component fragment. The solution you provided here is valid, or if you don't want or need to include variables in the fragment, you could go one level up and set new variables directly in the QueryRenderer (using props or state).
This could definitely be made more clear in the docs, so I'll update them to reflect this. Thanks for your patience! I hope this helps!
I think I'm going crazy here, maybe someone can explain to me what's going on. My QueryRenderer uses the following Query:
graphql`
query page_Query {
viewer {
id
...MountedRenderer_viewer
}
}
`
and this is what my createRefetchContainer looks like:
createRefetchContainer(
MountComponent,
graphql`
fragment MountedRenderer_viewer on User {
id
}
`,
graphql`
query OwnershipsRenderer_Query($show: Boolean!) {
viewer {
name @include(if: $show)
...MountedRenderer_viewer
}
}
`,
);
inside my MountComponent component I do this in componentDidMount:
this.props.relay.refetch(
{ show: true },
err => {
console.log('done!');
},
{ force: true },
);
I look into my store and I see that the data for "name" is fetched and merged with the store. However, the MountComponent does not get rerendered with the new data nor does it log "done". Shouldn't the MountComponent be subscribed to the viewer?
Your fragment needs to ask for name as well, it is only asking for id
@sibelius this is my createRefetchContainer now:
createRefetchContainer(
MountComponent,
graphql`
fragment MountedRenderer_viewer on User
@argumentDefinitions(show: { type: "Boolean", defaultValue: false }) {
id
name @include(if: $show)
}
`,
graphql`
query OwnershipsRenderer_Query($show: Boolean!) {
viewer {
...MountedRenderer_viewer @arguments(show: $show)
}
}
`,
);
still the same problem though, the store is being updated but the MountComponent is not rerendered / the callback does not executed
you need to also use renderVariables in this case
renderVariables = {
show,
}
https://facebook.github.io/relay/docs/en/refetch-container.html#arguments
@juhaelee I see that you had the same problem I had and @sibelius tried to help you as well did you solve your problem? I facing the same problema here https://github.com/facebook/relay/issues/2421
@CoericK my problem was that I was actually calling refetch with the wrong parameters. Had nothing to do with the graphql tag
Anyone still got problem?
I just refreshed fragmented component's key for workaround
@dehypnosis can you explain exactly what you did?
<component key={dynamicKey} />
i just changes component's key dynamically
Another possible reason, that confused me for some time today: you have a shouldComponentUpdate in the component that does not return true even if the data is updated.
Most helpful comment
Hey @MartinDawson, sorry for the delay in getting back to you on this issue!
This is actually expected behavior, and I'll try to expand on the answer from stack overflow. When
refetchis called and therefetchQueryis executed, Relay doesn't actually use the result of the query to re-render the component. All it does is normalize the payload into the store and fire any relevant subscriptions. This means that if the fetched data is unrelated to the data that the mounted container is subscribed to (e.g. using a totally different node id that doesn't have any data overlaps), then the component won't re-render.In this specific scenario, the reason why the container doesn't re-render, i.e. why it isn't subscribed to the changes fired by the
refetchQuery, is due to how subscriptions are set up. A subscription is basically a subscription to asnapshot, which basically represents a concrete fragment and the data and records associated with it at a given point in time -- when the records associated with a snapshot change, the subscription for that snapshot will be notified of changes.In this case, given that the fragment for the container has no variables, the snapshot that it will subscribe to will only be associated with the initial node; after refetch happens and the the store is updated, the records for the new node will have been updated, but the record associated with that original snapshot hasn't changed, so the container subscribed to it won't be notified.
This means that Refetch containers are only really meant to be used when you are changing variables in the component fragment. The solution you provided here is valid, or if you don't want or need to include variables in the fragment, you could go one level up and set new variables directly in the QueryRenderer (using props or state).
This could definitely be made more clear in the docs, so I'll update them to reflect this. Thanks for your patience! I hope this helps!