我一直在努力实现一个泛型<QueryRenderer/>
,它作为根级别的单一事实来源,最终分支成多个片段。我的初始实现在查询本身中静态定义了片段,并且会像这样接收组件作为道具......
...
class ComponentRenderer extends React.Component {
render() {
const ComponentRendererQuery = graphql`
query ComponentRendererQuery(
$globalId: ID
) {
viewer {
...Fragment1_viewer
...Fragment2_viewer
...Fragment3_viewer
...Etc_viewer
}
}
`
const Component = this.props.component;
return (
<QueryRenderer
environment={environment}
query={ ComponentRendererQuery }
variables={{
globalId: this.props.match.params.id
}}
render={({ error, props }) => {
if (error) {
return <div>{error.message}</div>
} else if (props) {
return <Component {...this.props} viewer={props.viewer} />
}
...
这个设置或多或少对我来说工作得很好,因为我没有<QueryRenderers/>
到处都是,只是个人喜好,我发现这个设置更干净一些。然而,我设法忽略了一个细节——我已经传播到根级查询中的所有片段都被请求了。我的假设是,由于活动的 React 组件保存了其余的片段,因此其他片段将被忽略,但事实并非如此。
我相信这种行为是由于中继如何预先构建您的数据模型,因此所有片段都在范围内。所以我的实现必然会破坏我的应用程序,但是它会导致相当多的过度获取并在服务器中为依赖于参数的任何片段创建一些异常(在此示例中,我传递 GraphQL 全局标识符以生成更详细的在另一页上查看)。
所以我尝试了另一种方法,认为我可以只预定义我的查询并将它们传递到<ComponentRenderer/>
我创建的这个泛型中。
const Fragment1Query = graphql`
query FragmentQuery {
viewer {
...Fragment1_viewer
}
}
`;
const Fragment2Query = graphql`
query FragmnetQuery {
viewer {
...Fragment2_viewer
}
}
`;
const hasId = this.props.match.params.id;
const Component = hasId ? Component1 : Component2
const Query = hasId ? Fragmen2 : Fragment2
return (
<ComponentRenderer
{...this.props}
component={Component}
query={Query}
/>
);
我已将查询重新定位到此处,并将先前分散到单个根查询中的每个先前片段分配给一个常量。曾经反对认为我很聪明,但没有完全理解 Relay 在构建时所做的事情。
所以问题在于 Relay 会提前构建所有内容,这意味着无论应用程序的状态如何保持不变。虽然从逻辑上讲,我应该能够有条件地决定将哪个片段呈现给<QueryRenderer/>
,但这似乎确实有效,因为 Relay 的优化之一取决于预先定义 GraphQL 查询和片段的结构。
所以有点陷入僵局。我发誓我在 GitHub 上的某个地方看到了一个示例,该示例完成了我正在尝试的操作,但没有保存链接。可能只需要将查询进一步向下移动到其他组件中……这实际上可能更明智,因为 Relay 的预期设计之一是强制组件控制自己的数据需求。
编辑:这是我今天遇到的一个示例,它解决了 Relay Classic 中的类似问题。不幸的是,发生了很大的变化,这并没有将所有内容完全转化为现代......但它给了我希望。使用 Relay 和 React-Native 时的条件片段或嵌入的根容器