首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RelayJS:查询任意数据的子组件

RelayJS:查询任意数据的子组件
EN

Stack Overflow用户
提问于 2015-12-22 08:18:40
回答 1查看 508关注 0票数 4

我正在构建一个仪表板,其中包含许多不同的小部件。用户可以添加和删除任何小部件,并按他们喜欢的任何顺序放置它们。每个小部件都有自己的数据需求。构建容器层次结构的正确中继方式是什么?

为了提供一些上下文,这是目前为止的体系结构:

Widget是一个组件,它接收一个config对象并相应地呈现相应的组件。

代码语言:javascript
复制
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组件包含用户添加的许多小部件。

代码语言:javascript
复制
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成为一个观众的领域。所以这个模式是这样的:

代码语言:javascript
复制
type Viewer {
  widget1: Widget1
  widget2: Widget2
}

type Widget1 {
  name,
  fieldOnlyForWidget1
}

type Widget2 {
  name,
  fieldOnlyForWidget2
}

然后,对于我的Widget容器,我尝试动态地插入片段。

代码语言:javascript
复制
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的可行性进行测试,并将很快进行更新。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-12-24 16:09:56

我认为这里的根本问题是,您试图让客户机在运行时根据服务器提供的一些数据(小部件名称)来决定请求的数据类型。这总是一个两步的过程,因此您不能在父进程中嵌套子片段来执行单个提取;因此,一旦您知道需要什么,就需要设置一个新的RootContainer或其他东西来启动一组新的查询。

但是,我认为您可以通过对图形本身中的小部件信息进行编码,从而使用常规嵌套将其作为单个获取来完成。这里的诀窍是使用GraphQL联合类型:文档

Union类型应该允许您将“仪表板”类型描述为具有“小部件”列表。如果您将"Widget“定义为一个联合类型,那么您可以拥有许多不同类型的小部件,并具有它们自己独特的字段和数据。

一旦服务器为联合类型提供服务,您就可以编写如下所示的仪表板中继容器:

代码语言:javascript
复制
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创建适当的小部件,如下所示:

代码语言:javascript
复制
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的理解(这并不多),这可能是最“中继式”的方式来模拟您的问题。

这有意义吗?

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34411292

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档