【问题标题】:How to map graphql query which is using union and fragments to render on page如何映射使用联合和片段在页面上呈现的graphql查询
【发布时间】:2018-02-01 20:05:44
【问题描述】:

架构:

type Link {
    items: [itemapi]      
    }

    type itemapi {
        id: ID!
        name: String!
        custom_attributes: [CUSTOM_ATTRIBUTES]
    }

    union CUSTOM_ATTRIBUTES = CustomString | CustomArray

   type CustomString {
    attribute_code: String
    value: String
  }

  type CustomArray {
    attribute_code: String
    value: [String]

  } 

  type Query {
    allLinks: Link!
  }
`;

功能:

const itemList= ({ data: {loading, error, allLinks }}) => {
  if (loading) {
    return <p>Loading ...</p>;
  }
  if (error) {
    return <p>{error.message}</p>;
  }

  return (
    <div className="itemList">
      { allLinks.items.map( aL => <div key={aL.id} className="items">{aL.???}</div> ) }
    </div>
  );
};
    const channelsListQuery = gql`
  query ChannelsListQuery {
      allLinks {
          items {
              id
              custom_attributes {
                  ... on CustomString{
                      value             
                  }
                  ... on CustomArray{
                      aliasVar: value
                  }
              }
          }
      }
  }
`;

问题是,我不知道如何正确映射它。我在模式中使用联合并在查询中使用片段来获取我需要的内容,然后在页面上呈现它。据我所知,查询数据是通过道具传递的,那么我如何才能访问联合/片段中的道具,如果可能的话,查询中的道具在CustomArray 中具有value 之类的别名?因为value 之一是字符串,第二个是字符串数组,但名称相同(value)我需要映射它并使用其中一个别名来从 api 获取数据。 我需要在地图功能中使用地图吗?

{"items":[{"id":"1","custom_attributes":[{"__typename":"CustomString","value":"<p>The sporty Joust Duffle Bag can't be beat - not in the gym, not on the luggage carousel, not anywhere. Big enough to haul a basketball or soccer ball and some sneakers with plenty of room to spare, it's ideal for athletes with places to go.<p>\r\n<ul>\r\n<li>Dual top handles.</li>\r\n<li>Adjustable shoulder strap.</li>\r\n<li>Full-length zipper.</li>\r\n<li>L 29\" x W 13\" x H 11\".</li>\r\n</ul>"},{"__typename":"CustomString","value":"/m/b/mb01-blue-0.jpg"},{"__typename":"CustomString","value":"/m/b/mb01-blue-0.jpg"},{"__typename":"CustomString","value":"/m/b/mb01-blue-0.jpg"},{"__typename":"CustomString","value":"49"},{"__typename":"CustomArray"},{"__typename":"CustomString","value":"container1"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"joust-duffle-bag"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"no_selection"}],"__typename":"itemapi"},{"id":"2","custom_attributes":[{"__typename":"CustomString","value":"<p>The sporty Joust blablablablablablablablablbalbalblalbalbla not on the luggage carousel, not anywhere. Big enough to haul a basketball or soccer ball and some sneakers with plenty of room to spare, it's ideal for athletes with places to go.<p>\r\n<ul>\r\n<li>Dual top handles.</li>\r\n<li>Adjustable shoulder strap.</li>\r\n<li>Full-length zipper.</li>\r\n<li>L 29\" x W 13\" x H 11\".</li>\r\n</ul>"},{"__typename":"CustomString","value":"/m/b/mb01-blue-0.jpg"},{"__typename":"CustomString","value":"/m/b/mb01-blue-0.jpg"},{"__typename":"CustomString","value":"/m/b/mb01-blue-0.jpg"},{"__typename":"CustomString","value":"49"},{"__typename":"CustomArray"},{"__typename":"CustomString","value":"container1"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"joust-duffle-bag"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"0"},{"__typename":"CustomString","value":"no_selection"}],"__typename":"itemapi"}],"__typename":"Link"}

【问题讨论】:

    标签: javascript reactjs graphql


    【解决方案1】:

    您可以修改查询以包含__typename。假设custom_attributes 是一个对象:

    query ChannelsListQuery {
        allLinks {
            items {
                id
                custom_attributes {
                    __typename
                    ... on CustomString{
                        value             
                    }
                    ... on CustomArray{
                        aliasVar: value
                    }
                }
            }
        }
    }
    
    Then inside your render function you can do something like this:
    return (
      <div className="itemList">
        {
          allLinks.items.map(item => 
            <div key={item.id} className="items">
            {
              item.__typename === 'CustomString'
              ?  <div>{item.custom_attributes.value}</div>
              :  item.custom_attributes.aliasVar.map(v => <div key={v}>{v}</div>)
            }
            </div>
          )
        }
      </div>
    );
    

    或者,您可以不使用__typename,而是检查aliasVar 属性的存在并进行相应的渲染,但类型名称是了解您正在处理的数据形状的一种可预测的方式。

    【讨论】:

    • 浏览器控制台中的错误:TypeError:无法读取未定义的属性“地图”。它根据第二个地图功能,在页面上是加载屏幕。而且我认为不应该为 item prop (allLinks.items) 执行嵌套函数,因为 value 位于其子项 (allLinks.item.custom_attributes) 中。
    • 抱歉,应该是item.custom_attributes.aliasVar,而不是item.aliasVar——更新了答案。
    • 它仍然显示我正在加载页面并且在浏览器中出现同样的错误。也许它无法读取别名道具?
    • 您可以将item 注销到控制台并在那里检查它以查看返回对象的结构是什么
    猜你喜欢
    • 2021-10-13
    • 1970-01-01
    • 2021-11-30
    • 2020-02-17
    • 2021-02-14
    • 2020-09-07
    • 1970-01-01
    • 2022-01-16
    • 2021-11-12
    相关资源
    最近更新 更多