graphql-jsrelayjsrelayrelaymodernreact-relay

fragment cannot be spread here as objects of type "Query"


Trying out relay with react and ran into this today. Here is what I've done so far.

Root Query:

query {
  tasks {
    id
    taskName
    taskStatus
    userId
  }
}

React component hierarchy

App   
 ↳--TaskList (props: tasks)
    ↳--TaskListItem (props: task)

Now due to the principle of colocation I know I have to write fragments in each component to describe their data needs.

TaskListItem.js

const TaskListItemContainer = createFragmentContainer(
    TaskListItem,
    graphql`
        fragment TaskListItem_task on task {
            id
            taskName
            taskDone
            authorId
        }
    `
);

TaskList.js

const TaskListContainer = createFragmentContainer(
    TaskList,
    graphql`
        fragment TaskList_tasks on task {
            tasks {
                ...TaskListItem_task
            }
        }
    `
);

App.js

<QueryRenderer
   environment={relayEnvironment}
   query={graphql`
       query AppQuery {
         ...TaskList_tasks
       }
     `
   }

When I run the relay compiler I get the following error.

Fragment "TaskList_tasks" cannot be spread here as objects of type "Query" can never be of type "task".

App.js (3:15)
2:             query AppQuery {
3:               ...TaskList_tasks
                 ^
4:             }

Not able to figure out how to organize the structure because of this problem. Should I modify the schema just to facilitate the structure and reuse of fragments on the client side?


Solution

  • A basic Fragment consists of five things:

    The selection set is one or more fields of the type you specify that you want to request when you use the Fragment. Think of the Fragment as a drop in replacement for a single selection set. If I have a query like this:

    query {
      foo
      bar
    }
    

    then { foo bar } is the selection set I'm requesting, in this case on the Query type (or whatever your query root operation type is called in your schema). So if I want to use a fragment, I would write:

    query {
      ...QueryFields
    }
    
    fragment QueryFields on Query {
      foo
      bar
    }
    

    In your code, you're trying to write a query like:

    query {
      ...TaskList_tasks
    }
    

    However, as the error indicates, the type associated with the TaskList_tasks fragment is task. But you're not replacing a selection set for a task type here, you're replacing a selection set for the Query type. So your request is not valid.

    TLDR; You need to change the type on your Fragment to Query:

    fragment TaskList_tasks on Query {
      tasks {
        ...TaskListItem_task
      }
    }