【问题标题】:Triggering a second GraphQL query based on data from initial query根据初始查询的数据触发第二个 GraphQL 查询
【发布时间】:2020-09-27 16:13:11
【问题描述】:

概述

WrappedApp 最初加载时,会向 GraphQL API 发送查询以获取数据(标签)。

完成此操作后,用户可以通过单击TagsList 中的标签将项目添加到WrappedApp 中的ShortList(参见下面的屏幕截图)。

问题

我怎样才能点击TagsList 中的标签(即在下面的示例中点击了安全)以触发名为GQLSIMILARTAGS 的第二个GraphQL 查询并将结果呈现在ShortList 组件数据上方或最少 console.log GQLSIMILARTAGS 查询的结果? GQLSIMILARTAGS 接受一个变量,该变量是被点击并添加到 ShortList 的标签。

我尝试了什么?

我尝试修改WrappedApp 中的addFavourite 函数以使用带有useQuery(GQLSIMILARTAGS) 的新GQLSIMILARTAGS 查询调用GQLFunc,但这可能不是最好的方法。

这是 Apollo GraphQL 查询代码。

graphclient.js




const client = new ApolloClient({
  uri: "https://xxxx.herokuapp.com/v1/graphql",
});

const GQLTAGS = gql`
  {
    tag(
      order_by: { tag_related_counts_aggregate: { count: desc } }
      where: { label: { _nin: ["None", "null"] } }
    ) {
      id
      label
      tag_related_counts_aggregate {
        aggregate {
          count
        }
      }
    }
  }
`;

        const GQLSIMILARTAGS = gql`
  query {
    tag(
      where: { tag_related_counts: { search_label: { _eq: "security" } } }
      distinct_on: id
    ) {
      label
      tag_related_counts {
        count
        other_label
        search_label
      }
    }
  }
`;

function GQLFunc(props) {
  const { loading, error, data } = useQuery(GQLTAGS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  let CallingApp = props.callingApp;
  if (data) return <CallingApp data={data.tag} />;
}

export { client, GQLTAGS, GQLFunc };

这是主要的WrappedApp.js 应用程序(编辑:根据@xadm 反馈更新为功能组件)。

       function WrappedApp(props) {
  const [filterText, setfilterText] = useState("");
  const [favourites, setFavourites] = useState([]);

  // update filterText in state when user types
  const filterUpdate = (value) => {
    setfilterText(value);
  };

  // add clicked name ID to the favourites array
  const addFavourite = (id) => {
    const newSet = favourites.concat([id]);
    setFavourites(newSet);
  };

  // remove ID from the favourites array
  const deleteFavourite = (id) => {
    //console.log(id);
    const newList = [...favourites.slice(0, id), ...favourites.slice(id + 1)];
    setFavourites(newList);
  };

  const hasSearch = filterText.length > 0;
  return (
    <div>
      {GQLSimilarFunc()}
      <header>
        <Greeting />
        <Search filterVal={filterText} filterUpdate={filterUpdate} />
      </header>
      <main>
        <ShortList
          data={props.data}
          favourites={favourites}
          simfunc={GQLSimilarFunc}
        />

        <TagsList
          data={props.data}
          filter={filterText}
          favourites={favourites}
          addFavourite={addFavourite}
        />
        {/* 
            Show only if user has typed in search.
            To reset the input field, we pass an 
            empty value to the filterUpdate method
          */}
        {hasSearch && (
          <button onClick={() => filterUpdate("")}> Clear Search</button>
        )}
      </main>
    </div>
  );
}

export default WrappedApp;

WrappedApp中使用的其他代码

import React, { Component, useState } from "react";
import { GQLSimilarFunc } from "./graphclient";

/* ############################ */
/* ##### Single tag ##### */
/* ############################ */

const Tag = ({ id, info, handleFavourite }) => (
  <li className={info.count} onClick={() => handleFavourite(id)}>
    {info.label} ({info.tag_related_counts_aggregate.aggregate.count})
  </li>
);


/* ##################### */
/* ##### Shortlist ##### */
/* ##################### */

const ShortList = ({ favourites, data, simfunc }) => {
  const hasFavourites = favourites.length > 0;
  const favList = favourites.map((fav, i) => {
    console.log(data.find((tag) => tag.id === fav).label);
    return (
      <Tag
        id={i}
        key={i}
        info={data.find((tag) => tag.id === fav)}
        //handleFavourite={(id) => deleteFavourite(id)}
        handleFavourite={() => simfunc()}
        /*handleFavourite={GQLSimilarFunc(
          data.find((tag) => tag.id === fav).label
        )}*/
      />
    );
  });
  //console.log(data.find((tag) => tag.id === 4436));

  return (
    <div className="favourites">
      <h4>
        {hasFavourites
          ? "Shortlist. Click to remove.."
          : "Click on a tag to shortlist it.."}
      </h4>
      <ul>{favList}</ul>
      {hasFavourites && <hr />}
    </div>
  );
};

/* ########################### */
/* ##### Tag list ##### */
/* ########################### */

const TagsList = ({ data, filter, favourites, addFavourite }) => {
  const input = filter;

  // Gather list of tags
  const tags = data
    // filtering out the tags that...
    .filter((tag, i) => {
      return (
        // ...are already favourited
        favourites.indexOf(tag.id) === -1 &&
        // ...are not matching the current search value
        !tag.label.indexOf(input)
      );
    })
    // ...output a <Name /> component for each name
    .map((tag, i) => {
      //console.log(tag.label);
      // only display tags that match current input string
      return (
        <Tag
          id={tag.id}
          key={i}
          info={tag}
          handleFavourite={(id) => addFavourite(id)}
        />
      );
    });

  /* ##### the component's output ##### */
  return <ul>{tags}</ul>;
};

/* ###################### */
/* ##### Search bar ##### */
/* ###################### */

// need a component class here
// since we are using `refs`
class Search extends Component {
  render() {
    const { filterVal, filterUpdate } = this.props;
    return (
      <form>
        <input
          type="text"
          ref="filterInput"
          placeholder="Type to filter.."
          // binding the input value to state
          value={filterVal}
          onChange={() => {
            filterUpdate(this.refs.filterInput.value);
          }}
        />
      </form>
    );
  }
}

这是我的index.js

import React from "react";
import ReactDOM from "react-dom";
import * as serviceWorker from "./serviceWorker";
import { ApolloProvider } from "@apollo/react-hooks";
import { client, GQLTags, GQLFunc } from "./graphclient";
import WrappedApp from "./WrappedApp";

/* ############################ */
/* ##### Single tag ##### */
/* ############################ */

ReactDOM.render(
  <ApolloProvider client={client}>
    <GQLFunc callingApp={WrappedApp} />
  </ApolloProvider>,
  document.getElementById("root")
);

【问题讨论】:

  • 如果查询与父子相关,则使用父子组件 - 只需在 GQLFunc 和 CallingApp 之间注入另一个组件级别。

标签: reactjs graphql apollo hasura


【解决方案1】:

可以这么简单

function GQLFunc(props) {
  const { loading, error, data } = useQuery(GQLTAGS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  //let CallingApp = props.callingApp;
  //if (data) return <CallingApp data={data.tag} />;
  if (data) return <GQLChild dataTag={data.tag} callingApp={props.callingApp} />;
}

function GQLChild(props) {
  const { loading, error, data } = useQuery(GQLSIMILARTAGS, {
    variables: {
      someSimilarRequiredVariableFromTagQueryResult: props.dataTag.something
    }
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  let CallingApp = props.callingApp;
  // pass data separately or combine into one `data` prop
  if (data) return <CallingApp dataSimilar={data} dataTag={props.dataTag} />;
}

【讨论】:

  • 用新的数据源包装一些准备好的应用程序是可以的。构建下一个“高于”应用程序的复杂性并寻找解决方法以将下一个数据/处理程序从/到查询传递是绝对不行。这是可能的(上下文或阿波罗本地状态),但这不是正确的方法。在正确的位置(在应用组件内部)使用查询和突变来重建您的应用。
  • &lt;WrappedApp /&gt; 转换为功能组件,在内部使用useQuery,将filterText 作为查询变量传递....但是(为避免其他问题/复杂性)您应该传递一个/主要变量- where 使用filterText 值构造的复杂条件对象)....useMutation(用于添加最喜欢的突变)可以放在&lt;WrappedApp /&gt; 中,也可以放在&lt;TagsList/&gt; 中(无需传递addFavourite 处理程序)。 .. 这一切都取决于 - 数据获取/渲染/更新的位置
  • 即使是 POC 也不应该朝这个方向走得更远,它会使简单的事情变得过于复杂。 “快速失败,更快成功”
  • 我已将WrappedApp 转换为函数组件并更新了问题中的代码。你能告诉我下一步该怎么做吗?
  • 假设起始情况,包装器&lt;GQLFunc/&gt; 读取标签并呈现&lt;CallingApp data={data.tag} /&gt; ....您的标签为props.data .... next ... useQuery(GQLSIMILARTAGS)(现在硬编码)在&lt;WrappedApp /&gt; ...它将获取一些具有类似项目的data ...您可以传递给一些子组件。
猜你喜欢
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-18
  • 2020-06-30
  • 1970-01-01
  • 2020-07-19
相关资源
最近更新 更多