I am using React and Apollo Client.
Based on a node type
value (nodes.type
) from a GraphQL response, I want to conditionally make a GraphQL request to either below query NodeTypeOne
or NodeTypeTwo
.
// MyBlock.gql
export default gql`
query NodeTypeOne {
getNodesOne {
nodes {
id
type
title
}
}
}
`;
export default gql`
query NodeTypeTwo {
getNodesTwo {
nodes {
id
type
title
}
}
}
`;
So in below React component I want to conditionally make a GraphQL request based on the node type
value.
import MyQuery from './MyBlock.gql';
const MyBlock = ({ data: myType }: Props) => {
const { data } = useQuery<GqlRes>(MyQuery);
const items =
data?.items?.map((node) => {
return {
id: node.id,
title: node.title,
};
}) || [];
return data?.items?.length ? (
<Slider items={items} />
) : null;
};
export default MyBlock;
How do I do this in a clean efficient way?
CodePudding user response:
There are several design patterns you can opt to solve problems. For your use case, the strategy design pattern will work smoothly. For code reference, you can google for a bunch of examples.
These are from my reference:-
https://dev.to/wecarrasco/strategy-pattern-with-javascript-dha
https://gist.github.com/Integralist/5736427
CodePudding user response:
As your query will target different resolvers, you cannot really create a single query from which you would target either the getNodesOne or getNodesTwo resolver.
useQuery on the other hand can take in parameter only a single, predefined query.
I would then go for 2 separate queries and use the apolloClient hook to conditionally call the right query:
// MyBlock.gql
export const QUERY1 = gql`
query NodeTypeOne {
getNodesOne {
nodes {
id
type
title
}
}
}
`;
export const QUERY2 = gql`
query NodeTypeTwo {
getNodesTwo {
nodes {
id
type
title
}
}
}
`;
import {QUERY1, QUERY2} from './MyBlock.gql';
const MyBlock = ({ data: myType }: Props) => {
const client = useApolloClient()
const [data, setData] = useState(null)
useEffect(() => {
client.query({query: MyType === '?' ? QUERY1 : QUERY2})
.then(({data}) => setData(data))
.catch((err) => console.error(err))
}, [myType])
if(!data) return null /* or a loader... */
const items =
data?.items?.map((node) => {
return {
id: node.id,
title: node.title,
};
}) || [];
return data?.items?.length ? (
<Slider items={items} />
) : null;
};
export default MyBlock;