AlexW.H.B. AlexW.H.B. - 3 months ago 56
Javascript Question

Relay.js is not resolving composed fragment correctly

I'm working on converting a Flux app to Relay.js and I'm running into some issues. I can't seem to get component fragment composition to work properly. The correct data comes back from the server, but the composed data is never passed back into the props of the parent component for some reason.

here's my code so far:

LibraryLongDescription.js

import React, {Component, PropTypes} from 'react';
import Relay from 'react-relay';
import DocumentTitle from 'react-document-title';
import Address from '../components/Address';
import Orders from '../pages/Orders';

export default class LibraryLongDescription extends Component {
constructor(props)
{
super(props);

this.state = {
library: {}
};

console.log(props);
if(props.library){
this.state.library = props.library;
}
}

render()
{
return (
<DocumentTitle title="Libraries">
<div>
{this.state.library.name}
<div className="row">
<Address type={"Address"} address={this.state.library.address} />
</div>

<div className="top-space-60">
<h3>Orders</h3>
<Orders />
</div>


</div>
</DocumentTitle>
);
}
}


export default Relay.createContainer(LibraryLongDescription, {
fragments: {
library: () => Relay.QL`fragment on Library {
id,
name,
address{
id
sanNumber,
addressLine1,
addressLine2,
city,
state,
zip
},
${Orders.getFragment('orders')}
}`,
}
});


Orders.js

import React, {Component, PropTypes} from 'react';
import Relay from 'react-relay';

class Orders extends Component {
constructor(props)
{
super(props);
console.log(props);
}

render()
{
return (<h1>This is where the order goes</h1>);
}
}

export default Relay.createContainer(Orders, {
fragments: {
orders: () => Relay.QL`fragment on Library {
orders(first: 10){
edges{
node{
id,
message_number,
order_total
}
}
pageInfo{
hasPreviousPage,
hasNextPage
}
}
}`
}
});


This does not resolve correctly. When I console log props in LibraryLongDescription.js I get all the values from that query, but I don't get anything from the Orders fragment. When I look to see what came over the network I get data in this form:

{
"data":{
"library":{
"id":"valid",
"name":"valid",
"address":{
correct data
},
"_orders1mpmPX":{
"edges":[
{
"node":{
correct data
},
"cursor":"correct data"
},
],
"pageInfo":{
correct data
}
}
}
}
}


but when I console log props from library Long description I don't see anything for orders. I also get this property:
__fragment__
which seems to not really have anything useful on it. Any help with this would be greatly appreciated. I've been searching the internet for solutions for hours. If there's any info I did not provide that would be of use let me know.

Answer

After spending a stupid amount of time trying to solve this issue I have discovered relay does not like you defining a type field in a fragment query. here's what I mean... the library query changed to this:

export default Relay.createContainer(LibraryLongDescription, {
    fragments: {
        library: () => Relay.QL`
            fragment on Library {
                id,
                name,
                address{
                    id
                    sanNumber,
                    addressLine1,
                    addressLine2,
                    city,
                    state,
                    zip
                },
                orders(first: 500){
                    ${Orders.getFragment('orders')}
                }
            }
        `,
    }
});

and the orders query changed to this:

export default Relay.createContainer(Orders, {
    fragments: {
        orders: () => Relay.QL`fragment on OrderConnection {
            edges{
                node{
                    id
                    purchaseDate
                }
            }
            pageInfo{
                hasPreviousPage
                hasNextPage
            }
        }`
    },
});

if you don't have some sort of root field like orders defined on the parent, relay won't know how to resolve that field back to the parent to be passed back into your child component. by doing this: orders(first: 500) you are declaring that name as a dependency for relay to pass it into that component. Without that name relay does not see your component requiring that name and it won't pass it. I hope this helps someone else out someday. I spent more than a full day trying to figure this one out.