问题
Overview
When WrappedApp
initially loads, a query is sent to the GraphQL API to fetch the data (Tags).
After this has completed a user can add an item to the ShortList
in WrappedApp
by clicking on a Tag in the TagsList
(see screenshot below).
Question
How can I get this click of a Tag in the TagsList
(i.e. security was clicked in the example below) to trigger the second GraphQL query named GQLSIMILARTAGS
and render the result above the ShortList
components data or at least console.log the result of the GQLSIMILARTAGS
query? GQLSIMILARTAGS
accepts a variable which would be the Tag that was clicked and added to ShortList
.
What have I tried?
I tried modifying the addFavourite
function in WrappedApp
to call GQLFunc
with the new GQLSIMILARTAGS
query with useQuery(GQLSIMILARTAGS)
but this may not be the best approach.
This is the Apollo GraphQL query code.
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 };
This is the main WrappedApp.js
App (edit: Updated to function component as per @xadm feedback).
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;
Other code used in 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>
);
}
}
and this is my 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")
);
回答1:
It can be as simple as
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} />;
}
来源:https://stackoverflow.com/questions/62266428/triggering-a-second-graphql-query-based-on-data-from-initial-query