I think there may be a problem with how Relay fulfils requests triggered by setVariables.
Here's an example Emailer component. The desired behaviour is for the emailSubject and emailBody fields to only be requested from the GraphQL if the user clicks the 'Email this customer' button.
However, trying to access the newly fetched fields in the onReadyStateChange function comes up with nothing:
Relay.createContainer(Emailer, {
initialVariables: {
emailing: false
},
fragments: {
customer: () => Relay.QL`
fragment on Customer {
name,
email,
picture,
emailSubject @include(if: $emailing)
emailBody @include(if: $emailing)
}
`
}
})
class Emailer extends Component {
this.emailCustomer = () => {
this.props.relay.setVariables(
{ emailing: true },
(state) => {
if (state.done) {
// Server has fulfilled request for emailSubject + emailBody fields, but these properties are not available on this.props.customer!
sendEmail({
recipient: this.props.customer.email,
emailSubject: this.props.customer.emailSubject,
emailBody: this.props.customer.emailBody
}, {
onDone: () => {
this.props.relay.setVariables({emailing: false});
}
})
}
}
)
}
render() {
return (
<div onClick={this.emailCustomer}>
{'Email this customer'}
</div>
)
}
}
In my real life analog to this component, I can see the request for emailSubject and emailBody being fulfilled by the server, and I can also see the props changing in the next render of the component — it's just trying to get the result of that request in the onReadyStateChange function falls flat!
What’s interesting is that wrapping the callback in a setTimeout with the timeout set to 0 does perform the expected behaviour.
I think I've answered a similar question on stackoverflow before http://stackoverflow.com/questions/34315742/props-value-after-receiving-setvariables-callback/34320309#34320309
From the docs
Note
setVariables does not immediately mutate variables, but creates a pending state transition. variables will continue returning the previous values until this.props has been populated with data that fulfills the new variable values.
All right. I feel like it's a very weird, unexpected API when you have a callback (one that even goes as far as responding to the state of the request) that doesn't have access to that kind of information though.
Seems like @xuorig already answered your question.
That callback is the called when RelayContainer is notified about the data being ready, but before the container has a chance to read all the new data from the RelayStore. You should be able to check access the props when the variables is updated.
If I needed to manipulate the returned data, where is the best place to do that? The componentWillReceiveProps seems to be not suitable for this task since the props might be changed by any other actions. However, I would want to manipulate the data just for the change made by this setVariables.
Most helpful comment
If I needed to manipulate the returned data, where is the best place to do that? The
componentWillReceivePropsseems to be not suitable for this task since the props might be changed by any other actions. However, I would want to manipulate the data just for the change made by thissetVariables.