My backend schema has a model, Request
, that uses a polymorphic association such that several different models all have-many Requests and a Request
can belong to any one of those different models.
I've got a React Component, RequestList
, that I want to be able to use in any of it's potential parent models.
Here's some sample code:
FooShowView.js
class FooShowView extends Component {
render() {
return (
<RequestList router={this.props.router} />
)
}
}
export default Relay.createContainer(ShowView, {
initialVariables: {
FooId: null
},
fragments: {
viewer: (variables) => {
return Relay.QL`
fragment on Viewer {
Foo(id: $FooId) {
id${ RequestList.getFragment('Foo') }
}
}`
`
}
}
});
RequestList.js
class RequestList extends Component {
renderRows = () => {
return this.props.requests.edges.map(edge => edge.node).map((intReq, i) => {
return (
<RequestRow
request={ intReq }
key={ i }
/>
);
});
}
render() {
return (
<Table>
{ this.renderRows() }
</Table>
);
}
};
export default Relay.createContainer(RequestList, {
fragments: {
foo: () => Relay.QL`
fragment on Foo {
requests(first: 10) {
edges {
node {
${ RequestRow.getFragment('request') }
}
}
}
}
`,
}
})
The problem is that now to render the RequestTable for another one of Request
's parents, say in the BarShowView
, I'd need to add a new fragment to RequestList
:
bar: () => Relay.QL`
fragment on Bar {
requests(first: 10) {
edges {
node {
${ RequestRow.getFragment('request') }
}
}
}
}
`,
And then Relay will spit out warnings that I need to provide both bar and foo as props to my List, even if it's not relevant to the current view.
Since Request
is associated with roughly 8 different models in my schema, this will quickly become unreasonable.
What is the correct way to create a reusable react component that will render the polymorphic children of whatever record I'm looking at?
What I ended up doing (in case someone runs into this) is just putting the RequestList
fragment on the root and just passing in variables so it only queries for the appropriate associated records. Much simpler than having to write a half dozen fragments. So my createContainer call now looks like:
export default Relay.createContainer(RequestList, {
initialVariables: {
fooId: null,
barId: null
}
fragments: {
viewer: () => Relay.QL`
fragment on Viewer {
requests(
first: 10,
fooId: $fooId,
barId: $barId
) {
edges {
node {
${ RequestRow.getFragment('request') }
}
}
}
}
`,
}
})
Note: if you're wondering why I'm passing up both fooID and barId instead of "requestableType" and "requestableID" it's because I'm using Elixir which doesn't support that type of polymorphism.