So, I am running into this problem where I am making filters while using the one graphql query. There's a child, parent & grandparent(these are different components). Now my query uses variables inside it, initially on load I set the variables in useState and it's working fine. Now when I click on a checkbox(which is insinde Child component) it passed its data(which is variable for new query) to the Grandparent and I am getting that, so I pass that data into the query variable. But it's not re-redering the query again with new variable. So my filters are not working.
Grand Parent
// handling all the product grid actions and data
function ProductGrid() {
const [queryVariables, setQueryVariables] = useState({first: 20});
console.log(queryVariables);
// get the variable object
const { loading, error, data, fetchMore} = useQuery(QUERY, {
variables: queryVariables
});
if (loading) return <p>Loading...</p>;
if (error) return (
<p>
{console.log(error)}
</p>
);
let productEdges = data.products.edges;
return(
<div className="outContainer">
{/* <PriceFilter/> */}
<TypeFilter getFilters={queryVariables => setQueryVariables(queryVariables)} />
{/* test button */}
<div className="product-grid">
{productEdges.map((element, index) => {
// formatting the price
let tempPrice = Math.floor(element.node.priceRange.minVariantPrice.amount);
let productPrice = new Intl.NumberFormat().format(tempPrice);
return(
<div className="container" key={index}>
<div className="image-container">
<img src={element.node.images.edges[0].node.transformedSrc} alt={element.node.title} />
</div>
<div className="product-title">{element.node.title}</div>
<div>{element.node.priceRange.minVariantPrice.currencyCode}. {productPrice}</div>
</div>
)
})}
</div>
{/* load more products button */}
<button
className="load-more"
onClick={()=>{
const endCursor = data.products.edges[data.products.edges.length - 1].cursor;
fetchMore({
variables: {
after: endCursor,
queryVariables
}
})
}}>
Load More
</button>
</div>
)
}
// graphql query for products fetching
const QUERY = gql`
query productFetch($first:Int, $after:String, $query:String){
products(first:$first, after: $after, query:$query){
edges{
node{
priceRange{
minVariantPrice{
amount
currencyCode
}
}
title
images(first:1){
edges{
node{
transformedSrc(maxWidth: 300)
}
}
}
}
cursor
}
pageInfo{
hasNextPage
}
}
}
`
Parent
// ************** Parent ***************
function TypeFilter(props) {
// assume other code is here for a modal pop and
accordion inside here
// passing the prop to checkbox component here and
getting back new state which we use as a callback for
it's parent
<TypeCheckBox getCheckState={queryVariables =>
props.getFilters(queryVariables)} />
}
Child
// ************** Child *****************
let result = "";
let variables =
{
first: 28,
query: ""
};
function TypeCheckBox(props){
// below function returns variables for apollo query
const handleCheckChange = (event) => {
setState({ ...state, [event.target.name]: event.target.checked });
if(event.target.checked){
// pass this value into the productGrid component
if(counter > 1){
result += "&";
}
result = `${result}product_type:${event.target.value}`;
counter++;
// setting filter type to result
console.log(result);
variables.query = result;
console.log(variables);
return props.getCheckState(variables);
}else{
result = result.replace(`product_type:${event.target.value}`, "");
result = removeLast(result, "&");
counter--;
// setting filter type to result
console.log(`in else ${result}`);
variables.query = result;
console.log(variables);
return props.getCheckState(variables);
}
};
}
return (
<FormGroup column>
<FormControlLabel
control={<Checkbox checked={state.checkedBridal} value="Bridal" onChange={handleCheckChange} name="checkedBridal" />}
label="Bridals"
/>
)
}
I tried using useEffect on useQuery in GrandParent, but then the returned constants don't have access outside, like
useEffect(() => {
const { loading, error, data, fetchMore} = useQuery(QUERY, {
variables: queryVariables
});
}, [queryVariables])
Thanks you soo much for your answers ^^
So, I figured out a solution since no one answered it so I am gonna answer it.
first, you need to add refetch and fetch-policy in useQuery hook as
const { loading, error, data, fetchMore, refetch, networkStatus } = useQuery(
QUERY,
{
variables: queryVariables,
// notifyOnNetworkStatusChange: true,
fetchPolicy: "network-only"
}
);
Then you need to make a separate function with the same name as your props that you're passing to your children and use the spread operator with queryVariables to expand and refetch the query with new variables as
const getFilters = queryVariables => {
setQueryVariables({ ...queryVariables });
refetch();
};
Hope this is helpful to someone ^^