Relay: [Modern-rc.2] RelayStaticSelector is searching for a wrong prop name

Created on 21 Apr 2017  路  33Comments  路  Source: facebook/relay

In rc.2, queries without fragments work fine. Queries with fragments started to break because Relay is not able to find fragment data in the response.

The query is assembled correctly, and the server response is in the right shape. However, when I pass the expect prop down to the Relay(MyContainer), I get this error from RelayStaticSelector -

Warning: RelayStaticSelector: Expected object to contain data for fragment `myProp`,
got `{"__fragments":{"MyContainer_myProp":{}},"__id":"client:root:topquery"}`. 
Make sure that the parent operation/fragment included fragment `...myProp`

Seems like StaticSelector is ignoring the expect prefix for the fragment, and is sniffing for myProp instead of MyContainer_myProp which is how it is embedded in the query

Most helpful comment

This is fixed in d7c5750, which will go out in the next RC. Thanks again all for the bug reports and repro examples!

All 33 comments

I'm getting the same issue here.

+1 Same here

I can confirm this!

Same thing :)

@robrichard thanks for the repro. Nothing immediately jumps out in the code as being off, this should work.

I am having these exact same problems, which prompted #1685

From what I can tell, there are no test cases that cover composition with child components, so no regressions got raised between RCs.

This is effectively tested in https://github.com/facebook/relay/blob/master/packages/react-relay/modern/__tests__/ReactRelayFragmentContainer-test.js#L202

Obviously that isn't sufficient though! I think what's happening here is that something is inconsistent about the way the compiler generates the fragment name at the query vs at the fragment.

FWIW, todo-modern also breaks with the same error if I change it to skip the compat layer.

Here's the smallest delta to the original example that will demonstrate this issue https://github.com/relayjs/relay-examples/compare/master...eugene1g:master

Maybe not obvious but important: while the problem started showing up in rc2, the core issue was _not_ introduced between rc1 and rc2. In rc1, all components were forced through the compat layer, even the ones trying to use the modern path instead. Therefore, the code response for this bug was not in the execution path prior to rc2. So the problem existed in rc1 as well, it's just up until rc2 the culprit code was not called.

Damn, wish I'd looked for this issue earlier, I just wasted a good few hours on this assuming it was my error. But yes, data for child fragments isn't being constructed correctly to pass down the render tree.

Thanks for the extra details. I debugged and reproduced this, it looks like this was introduced in RC2 and is caused by the output of graphql tags not being unwrapped when in full-Modern mode. We're working on a fix.

Well I'm not getting any errors but the fragment data is null. Any fixes so far?

We'll follow up here, stay tuned!

This is fixed in d7c5750, which will go out in the next RC. Thanks again all for the bug reports and repro examples!

Awesome!

when will it release?

@saudpunjwani101 I believed this was released with rc3.

I'm still getting { __fragments: { postList_posts: {} }

I don't see any change in rc.3 is this really fixed?

some tests are throwing some warnings:

  • packages/react-relay/classic/environment/__tests__/RelayFragmentSpecResolver-test.js:
console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelaySelector: Expected object to contain data for fragment `RelayFragmentSpecResolver_user`, got `{}`. Make sure that the parent operation/fragment included fragment `...RelayFragmentSpecResolver_user`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelaySelector: Expected object to contain data for fragment `RelayFragmentSpecResolver_user`, got `{}`. Make sure that the parent operation/fragment included fragment `...RelayFragmentSpecResolver_user`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelaySelector: Expected object to contain data for fragment `RelayFragmentSpecResolver_user`, got `{}`. Make sure that the parent operation/fragment included fragment `...RelayFragmentSpecResolver_user`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelaySelector: Expected object to contain data for fragment `RelayFragmentSpecResolver_users`, got `{}`. Make sure that the parent operation/fragment included fragment `...RelayFragmentSpecResolver_users`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelaySelector: Expected object to contain data for fragment `RelayFragmentSpecResolver_users`, got `{}`. Make sure that the parent operation/fragment included fragment `...RelayFragmentSpecResolver_users`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelaySelector: Expected object to contain data for fragment `RelayFragmentSpecResolver_users`, got `{}`. Make sure that the parent operation/fragment included fragment `...RelayFragmentSpecResolver_users`.
  • packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-test.js
console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelayModernSelector: Expected object to contain data for fragment `UserFragment`, got `{}`. Make sure that the parent operation/fragment included fragment `...UserFragment`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelayModernSelector: Expected object to contain data for fragment `UserFragment`, got `{}`. Make sure that the parent operation/fragment included fragment `...UserFragment`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelayModernSelector: Expected object to contain data for fragment `UserFragment`, got `{}`. Make sure that the parent operation/fragment included fragment `...UserFragment`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelayModernSelector: Expected object to contain data for fragment `UsersFragment`, got `{}`. Make sure that the parent operation/fragment included fragment `...UsersFragment`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelayModernSelector: Expected object to contain data for fragment `UsersFragment`, got `{}`. Make sure that the parent operation/fragment included fragment `...UsersFragment`.
    console.error node_modules/fbjs/lib/warning.js:36
      Warning: RelayModernSelector: Expected object to contain data for fragment `UsersFragment`, got `{}`. Make sure that the parent operation/fragment included fragment `...UsersFragment`.

Hmm. I was able to reproduce this on RC2 using relay-examples/todo-modern and confirmed that d7c5750 fixed the issue. I can no longer reproduce this with todo-modern on master.

@saudpunjwani101 If you're still seeing issues, make sure that you've updated to RC3 (if you're not using yarn, it might be easiest to just clear out node_modules). If you still see the problem, can you share a repro?

rc.3 fixed this

please make sure you move everything from react-relay/compat to only react-relay

Anyone still seeing this on RC3? Cool to close?

LGTM.

RC3 fixed this for me - other similar issues might be related but must have a different root cause.

I am still seeing this issue on RC3..
Trying to figure out what and where it fails, it seems like when adding queries to the root QueryRenderer, it will get and pass down data, but it will not get fragments.

Altho the fragments are in the query to the server itself.

@stoffern FWIW RC3 works for my fragments whether they are at the top query or inside other fragments, so the patch fixed at least those specific use-cases. Perhaps open another issue to track the other issue?

This is more or less my code..

PS:

  • I am using a classic Relay.RelayNetworkLayer
  • babelrc = ["relay", {"compat": true, "schema": "schema/schema.graphql"}],
import Relay from 'react-relay/classic'
import {createFragmentContainer, graphql, QueryRenderer} from 'react-relay/compat'

EditProfile = createFragmentContainer(EditProfile, graphql`
  fragment EditProfile_query on Viewer {
    user{
        id
        firstName
        lastName
        gender
        email
        profileImage{
            url
        }
    }
  }
`)


export default class EditProfileWrapper extends Component{
    render(){
        return (
            <QueryRenderer
            environment={Relay.Store}
            query={graphql`
              query EditProfileWrapperQuery {
                viewer {
                  ...EditProfile_query
                }
              }
            `}
            variables={{}}
            render={({error, props}) => {
              if (error)  this.props.userActions.logout()
              else if (props) return <EditProfile user={this.props.viewer.user} />
              else return <EditProfile query={null} />
            }}
          />
        )       
    }
}

stoffern, that example uses Relay in compat and classic modes. I openned this specific ticket to track a specific issue within Relay modern when compat/classic code was working perfectly fine for me. That specific issue (within modern) has been fixed with RC3, but sounds like there is another problem - with similar symptoms! - hiding elsewhere. Would you please open another ticket reporting this so the team and other contributors have a dedicated place to track it? There are ~100 tickets and it'll be difficult to triage them if each one touches on multiple unrelated issues. Thanks!

@eugene1g thanks for the heads up 馃槈
Just made a new issue on it here:
https://github.com/facebook/relay/issues/1732

I seem to be having the same issue, even with RC3 - unless there's some user error I can't find? I have very similar code:

import { QueryRenderer, graphql } from 'react-relay';
class HistoryContainer extends Component {
  render() {
    return (
      <View>
        <QueryRenderer
          environment={environment}
          query={graphql query HistoryContainerQuery {
                  viewer {
                    allJournalEntries {
                      count
                      edges {
                        node {
                          ...HistoryList_viewer
                        }
                      }
                    }
                  }
                }
            }
          render={({ error, props }) => {
            if (error) {console.log("error"); }
            else if (props) {
              const count = props.viewer.allJournalEntries.count;
              return (
                <View>
                  <Text>
                    There are this many entries: {count}
                  </Text>
                  <HistoryList viewer={props.viewer} />
                </View>
              );
            } else {
              return <Text>Loading...</Text>;
            }
            return null;
          }}
        />
      </View>
    );
  }
}

export default HistoryContainer;

And then the list with fragmentcontainer:

export default createFragmentContainer(HistoryList, {
  viewer: graphql`
    fragment HistoryList_viewer on JournalEntry {
      huntDate
      animalData {
        danishName
      }
    }
  `,
});

The count property populates correctly, and the fragment and root query works just fine in GraphiQL, but I get an error similar to this one, although on RelayModernSelector instead:

Expected object to contain data for fragment `HistoryList_viewer`, got `{"allJournalEntries":
{"count":2,"edges":[{"node":{"__fragments":{"HistoryList_viewer":
{}},"__id":"cj2khg79yhen70132xtqpizz3"}},{"node":{"__fragments":{"HistoryList_viewer":
{}},"__id":"cj2ki9lt3ja1o0134lf8jes18"}}]}}`. Make sure that the parent operation/fragment 
included fragment `...HistoryList_viewer`.

Yeah I had the same problem, I resolved it by changing my fragment. Try doing,

  export default createFragmentContainer(HistoryList, {
       viewer: graphql`
        fragment HistoryList_viewer on //change to whatever the name also on schema.graphql {
        edges {
          node {
            huntDate
            animalData {
               danishName
           }
      }
  `,
});

And your query will change into

      graphql query HistoryContainerQuery {
         viewer {
            allJournalEntries {
               count
               ...name_of_fragment
              }
            }
          }

Thanks for answering, although I'm not sure I understand what you want me to change?

The generated query in __ generated __/HistoryContainerQuery.graphql.js looks like this with my code:

query HistoryContainerQuery {
  viewer {
    allJournalEntries {
      count
      edges {
        node {
          ...HistoryList_viewer
          id
        }
      }
    }
    id
  }
}

fragment HistoryList_viewer on JournalEntry {
  huntDate
  animalData {
    danishName
    id
  }
}

which works fine in GraphiQL as well. My schema.graphql has a type for both JournalEntry and AnimalData:

type JournalEntry implements Node {
  animalData(filter: AnimalDataFilter): AnimalData
  id: ID!
  // other props...
}

type AnimalData implements Node {
  danishName: String!
  id: ID!
  // other props...
}

Did I miss something? I noticed that the correct IDs for the nodes are returned and printed along with the error, but the data expected/declared in the fragment is an empty object {} - but if I ask for the same structure of data in the QueryRenderer (or GraphiQL), the expected data is returned just fine

EDIT: I solved my problem by passing the parent data to child components through props, see this SO post + my (jhm) comments: https://stackoverflow.com/a/43911492/1409779

There seem to be some lack of clarity if the rules that define Fragment and Query naming requirements.

Having followed the naming as defined in the Relay Modern tutorials we have yet to run into this issue.

However, I have run into issues with Babel and the graphql runtime when parsing the queries, fixed these by switching to the following packages :
"dependencies": { "react": "16.0.0-alpha.6", "react-native": "0.44.0", "react-navigation": "^1.0.0-beta.9", "react-relay": "dev" }, "devDependencies": { "babel-jest": "20.0.1", "babel-plugin-relay": "dev", "babel-preset-react-native": "1.9.2", "jest": "20.0.1", "react-test-renderer": "16.0.0-alpha.6", "relay-compiler": "dev" },

PS: Formatting the above code brackets is not working for me... Why the carriage returns aren't being detected is frustrating...

Was this page helpful?
0 / 5 - 0 ratings