Relay: Relay.setVariables results not accessible via onReadyStateChange callback

Created on 29 Mar 2016  Â·  4Comments  Â·  Source: facebook/relay

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.

Most helpful comment

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.

All 4 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

staylor picture staylor  Â·  3Comments

janicduplessis picture janicduplessis  Â·  3Comments

xuorig picture xuorig  Â·  4Comments

amccloud picture amccloud  Â·  3Comments

derekdowling picture derekdowling  Â·  3Comments