我正在构建一个仪表板,其中包含许多不同的小部件。用户可以添加和删除任何小部件,并按他们喜欢的任何顺序放置它们。每个小部件都有自己的数据需求。构建容器层次结构的正确中继方式是什么?
为了提供一些上下文,这是目前为止的体系结构:
Widget是一个组件,它接收一个config对象并相应地呈现相应的组件。
class Widget extends React.Component {
render() {
const {widget} = this.props;
// widgetMap is a map that maps string to React component
const ActualWidget = widgetMap.get(widget.component);
return (
<ActualWidget data={widget.data} />
);
}
}
export default Relay.createContainer(Widget, {
fragments: {
data: () => Relay.QL`
fragment on ??? {
# What should be here since we don't know what will be rendered?
}
`
}
});Dashboard组件包含用户添加的许多小部件。
class Dashboard extends React.Component {
renderWidgets = () => {
return this.props.widgets.map(widget => {
return <Widget widget={widget}/>;
});
};
render() {
return (
<div>
<span>Hello, {this.props.user.name}</span>
{this.renderWidgets()}
</div>
);
}
}
export default Relay.createContainer(Dashboard, {
fragments: {
// `user` fragment is used by Dashboard
user: () => Relay.QL`
fragment on User {
name
}
`,
// Each widget have different fragment,
// So what should be here?
}
});更新
我试着让每一个ActualWidget成为一个观众的领域。所以这个模式是这样的:
type Viewer {
widget1: Widget1
widget2: Widget2
}
type Widget1 {
name,
fieldOnlyForWidget1
}
type Widget2 {
name,
fieldOnlyForWidget2
}然后,对于我的Widget容器,我尝试动态地插入片段。
export default Relay.createContainer(Widget, {
initialVariables: {
component: 'Widget1' // Trying to set the string here
}
fragments: {
data: (variables) => Relay.QL`
fragment on Viewer { # We now know it is Viewer type
# This didn't work because `variables.component` is not string! :(
${widgetMap.get(variables.component).getFragment('viewer')}
}
`
}
});这不管用。我相信Relay静态地解析了QL,所以它无法组成动态片段。不过,这只是我的猜测。
我正在对每个小部件使用RootContainer的可行性进行测试,并将很快进行更新。
发布于 2015-12-24 16:09:56
我认为这里的根本问题是,您试图让客户机在运行时根据服务器提供的一些数据(小部件名称)来决定请求的数据类型。这总是一个两步的过程,因此您不能在父进程中嵌套子片段来执行单个提取;因此,一旦您知道需要什么,就需要设置一个新的RootContainer或其他东西来启动一组新的查询。
但是,我认为您可以通过对图形本身中的小部件信息进行编码,从而使用常规嵌套将其作为单个获取来完成。这里的诀窍是使用GraphQL联合类型:文档
Union类型应该允许您将“仪表板”类型描述为具有“小部件”列表。如果您将"Widget“定义为一个联合类型,那么您可以拥有许多不同类型的小部件,并具有它们自己独特的字段和数据。
一旦服务器为联合类型提供服务,您就可以编写如下所示的仪表板中继容器:
var Dashboard = Relay.createContainer(DashboardComponent, {
fragments: {
dashboard: () => { console.log("dashboard query"); return Relay.QL`
fragment on Dashboard {
widgets {
_typename
${FooWidget.getFragment("widget")}
${BarWidget.getFragment("widget")}
}
}
`},
}
});请注意在联合类型上定义的特殊"__typename“字段(有关一些细节,请参见这个问题 )。然后,您的仪表板组件可以使用this.props.dashboard.widgets迭代所有小部件,并基于__typename创建适当的小部件,如下所示:
var widgets = this.props.dashboard.widgets.map((widget) => {
if (widget.__typename == "FooWidget") {
return <FooWidget widget={widget} />
} else if (widget.__typename == "BarWidget") {
return <CountdownWidget widget={widget} />
}
})我很肯定这会成功,但我自己一点也没试过。根据我对Relay的理解(这并不多),这可能是最“中继式”的方式来模拟您的问题。
这有意义吗?
https://stackoverflow.com/questions/34411292
复制相似问题