Hi folks,
I'm trying to compose some fragments and have also opted to not use the viewer pattern. I've got a QueryRenderer that uses the following root query ...
const query = graphql`
query TeamsQuery {
...TeamsPage_teams
}
`;
As you can see, I'm spreading a fragment right into the root Query type.
Is this allowed?
It doesn't seem like Relay understands the prop should be named teams, based on the naming convention. If I try to pull teams off props, it's not there.
function render({ props }) {
if (!props) {
return <TeamsPageLoading />;
} else {
const { teams } = props;
return <TeamsPage teams={teams} />;
}
}
can you test this?
function render({ props }) {
if (!props) {
return <TeamsPageLoading />;
} else {
return <TeamsPage {...props} />;
}
}
then in TeamsPage component please check what is props available. im not sure either.
class TeamsPage extends Component{
render(){
console.log(this.props)
}
}
@nosykretts The properties will be the meta props that relay uses, such as __fragments and __id, etc. Typically there'd be a property for the top level field in the query. In my example, the top level field would come from the spread-in fragment (which works in GraphQL, just not relay).
I don't think the spreading of props goes with the proper conventions of React. It just doesn't seem intended.
Alright, well, I got it to work but it's not very intuitive, which leads me to believe that it's not quite intended to be used this way. Although, given that spreading a fragment into a root query leaves no room for providing a name for the prop, I'm not sure what I expected Relay to do? There's not really a top level field to reference in the response, which feels kind of strange. Perhaps it'd be nice if you could alias the fragment that is about to be spread, or maybe it wouldn't, I'm not sure ...
const query = graphql`
query TeamsQuery {
teams: ...TeamsPage_query
}
`;
But, if you are spreading a fragment into the root query, you can just think of props as the query response object, and pass that down to your fragment containers. No need to pull off a prop, from props, because the fragment containers keep track of the data they should have access to. This is similar to .NET's Entity Framework proxy classes.
So, this works if you just use the response data like so ..
const query = graphql`
query TeamsQuery {
...TeamsPage_query
}
`;
function render({ props }) {
if (props) {
return <TeamsPage query={props} />;
} else {
return <TeamsPageLoading />;
}
}
export default function Teams() {
return (
<QueryRenderer
query={query}
render={render}
environment={relayEnvironment}
/>
);
}
And then for your first fragment container ...
function TeamsPage({ query }) {
return (
<Template>
<div className="row mb-4">
<div className="col-12">
<h1>Teams</h1>
<hr />
</div>
</div>
<div className="row">
<div className="col-12">
<TeamList query={query} />
</div>
</div>
</Template>
);
}
export default createFragmentContainer(
TeamsPage,
graphql`
fragment TeamsPage_query on Query {
...TeamList_query
}
`
);
As you can see, I'm just passing the complete response along, naming it query. This would basically happen until you get to a fragment container that actually begins using specifics fields, at which point typical examples from the docs would become more familiar ...
function TeamList({ query }) {
const { teams } = query;
return (
<ul className="list-unstyled">
{teams.map(t => <TeamListItem key={t.name} team={t} />)}
</ul>
);
}
export default createFragmentContainer(
TeamList,
graphql`
fragment TeamList_query on Query {
teams {
name
...TeamListItem_team
}
}
`
);
Final thoughts ...
I guess I could not put my QueryRenderer so high up in the component tree. I'd move the QueryRenderer down, closer to the component that actually needs it. This might end up in a lot more QueryRenderers. I'm not sure what the dos and donts on number of QueryRenderer are.
Thx @ryancole ... Your experiment just saved my day.
yes you can
check this out https://github.com/sibelius/ReactNavigationRelayModern/pull/18
Happy to see this question answered!
@ryancole you have saved me after days of pulling out my hair. Thank you!
Most helpful comment
Alright, well, I got it to work but it's not very intuitive, which leads me to believe that it's not quite intended to be used this way. Although, given that spreading a fragment into a root query leaves no room for providing a name for the prop, I'm not sure what I expected Relay to do? There's not really a top level field to reference in the response, which feels kind of strange. Perhaps it'd be nice if you could alias the fragment that is about to be spread, or maybe it wouldn't, I'm not sure ...
But, if you are spreading a fragment into the root query, you can just think of
propsas the query response object, and pass that down to your fragment containers. No need to pull off a prop, fromprops, because the fragment containers keep track of the data they should have access to. This is similar to .NET's Entity Framework proxy classes.So, this works if you just use the response data like so ..
And then for your first fragment container ...
As you can see, I'm just passing the complete response along, naming it
query. This would basically happen until you get to a fragment container that actually begins using specifics fields, at which point typical examples from the docs would become more familiar ...Final thoughts ...
I guess I could not put my
QueryRendererso high up in the component tree. I'd move theQueryRendererdown, closer to the component that actually needs it. This might end up in a lot moreQueryRenderers. I'm not sure what the dos and donts on number ofQueryRendererare.