SWR with graphql-request how to add variables in swr? - reactjs

I want to add variables to my swr which fetch using graphql request. this is my code
import { request } from "graphql-request";
import useSWR from "swr";
const fetcher = (query, variables) => request(`https://graphql-pokemon.now.sh`, query, variables);
export default function Example() {
const variables = { code: 14 };
const { data, error } = useSWR(
`query GET_DATA($code: String!) {
getRegionsByCode(code: $code) {
code
name
}
}`,
fetcher
);
if (error) return <div>failed to load</div>;
if (!data) return <div>loading...</div>;
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
but I dont know how to add variables into swr fetcher as I know useSWR(String, fetcher) string is for query, and fetcher for fetch function, where I can put the variables?

You can use Multiple Arguments, you can use an array as the key parameter for the useSWR react hook.
import React from "react";
import { request } from "graphql-request";
import useSWR from "swr";
const fetcher = (query, variables) => {
console.log(query, variables);
return request(`https://graphql-pokemon.now.sh`, query, variables);
};
export default function Example() {
const variables = { code: 14 };
const { data, error } = useSWR(
[
`query GET_DATA($code: String!) {
getRegionsByCode(code: $code) {
code
name
}
}`,
variables,
],
fetcher
);
if (error) return <div>failed to load</div>;
if (!data) return <div>loading...</div>;
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
The function fetcher still accepts the same 2 arguments: query and variables.

SWR author here!
Agreed that this is a critical feature to have, that's why since v1.1.0, SWR keys will be serialized automatically and stably. So you can safely do this:
useSWR(['query ...', variables], fetcher)
While variables can be a JavaScript object (can be nested, or an array, too), and it will not cause any unnecessary re-renders. Also, the serialization process is stable so the following keys are identical, no extra requests:
// Totally OK to do so, same resource!
useSWR(['query ...', { name: 'foo', id: 'bar' }], fetcher)
useSWR(['query ...', { id: 'bar', name: 'foo' }], fetcher)
You can directly pass an object as the key too, it will get passed to the fetcher:
useSWR(
{
query: 'query ...',
variables: { name: 'foo', id: 'bar' }
},
fetcher
)
You can try it out by installing the latest version of SWR, let me know if there's any issue :)

The solution from slideshowp2 did not help me since it resulted in an infinite loop.
Don't pass an object to the useSWR function since they change on every re-render. Pass the variables directly:
const fetcher = (query, variables) => {
console.log(query, variables);
return request(`https://graphql-pokemon.now.sh`, query, variables);
};
export default function Example() {
const { data, error } = useSWR(
[
`query GET_DATA($code: String!) {
getRegionsByCode(code: $code) {
code
name
}
}`,
14,
],
(query, coder => fetcher(query, { code })
);
if (error) return <div>failed to load</div>;
if (!data) return <div>loading...</div>;
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

Related

useSWR return { null, null } for valid request

I'm trying to make a request to Firebase real-time database with useSWR in my next.js project, but for some reason it always returns null for both data and error variables.
import useSWR from 'swr';
const LastSales: NextPage = () => {
const [sales, setSales] = useState<Sale[]>([]);
const { data, error } = useSWR(
'https://my-app-12345-default-rtdb.firebaseio.com/sales.json'
);
useEffect(() => {
if (!data) return;
const salesArr = [];
for (const key in data) {
salesArr.push({
id: key,
username: data[key].username,
volume: data[key].volume,
});
}
setSales(salesArr);
}, [data]);
if (error) return <p>Failed to load.</p>;
if (sales.length === 0) return <p>Loading...</p>;
return <div>Sales List</div>
Making the same request with fetch works perfectly fine, but takes up 10x as many lines of code. Why are both data and error equal to null?
According to doc, you need to have a fetcher to define how it will be called.
const fetcher = (url) => fetch(url).then((res) => res.json());
export default function App() {
const { data, error } = useSWR(
"https://api.github.com/repos/vercel/swr",
fetcher
);

React-query and Typescript - how to properly type a mutation result?

I have a simple hook that wraps the axios call in React Query:
function useInviteTeamMember(
onSuccess?: Handler,
onError?: Handler,
): UseMutationResult<User> {
const mutation = useMutation(
(payload: InviteMutationVars) => {
return postInviteTeamMember(payload);
},
{
onSuccess: (data) => {
...
The issue I have is that from the above definition you would expect the result to be of type User.
Even in that onSuccess handler (data) is according to intellisense of type User.
But it's not.
To get the actual User object I have to do data['data'].
The actual post function is the root cause I think, since it types the Promise with :
export function postInviteTeamMember(payload: InviteMutationVars): Promise<User> {
return client.post('/user/invite/team', payload);
}
So how can I rewrite this code so that the type of 'data' is correct?
You can transform the response yourself:
export function postInviteTeamMember(payload: InviteMutationVars): Promise<User> {
return client.post('/user/invite/team', payload).then(response => response.data);
}
If you type the return object in your mutation function, typescript will show that type on the onSuccess parameter.
Let's create a category as an example.
Here we have the mutation function, which we type the return as an object with key category and a value of type ExampleCategoryT.
Typescript will know this function has a return type of : Promise< ExampleCategoryT>, so there is no need to explicitly write it (but you could if you wanted ofcourse).
export async function createCategory(category: CreateCategoryArg) {
const { data } = await http.post<{ category: ExampleCategoryT }>(
'/categories',
{ category }
);
return data.category;
}
In the useMutation function, the category argument will have a type of ExampleCategoryT.
const { mutate: createCategoryMutation } = useMutation(
createCategory,
{
onSuccess: (category) => {
queryClient.setQueryData<ExampleCategoryT[]>(
['categories'],
(oldData = [) => [...oldData, category]
);
},
onError: (error) => {
// ...
},
}
);

Graphql subscription not getting client-side variables

I am trying to subscribe to a graphql-yoga subscription using apollo-client useSubscription hook
import React from 'react';
import {useSubscription,gql} from '#apollo/client';
const SUB_NEW_MSG = gql`
subscription SUB_NEW_MSG($chatRoom:ID!)
{
newMessage(chatRoom:$chatRoom)
}`;
function NewMsg(){
const { loading,error,data } = useSubscription(SUB_NEW_MSG,{
variables:{
chatRoom: "608851227be4796a8463607a",
},
});
if(loading) return <p>loading...</p>;
if(error) return <p>{error}</p>;
console.log(data);
return <h4>New Message:{data.newMessage}</h4>;
}
Network Status
But gives an error-
Error: Objects are not valid as a React child (found: Error: Variable "$chatRoom" of required type "ID!" was not provided.). If you meant to render a collection of children, use an array instead.
The schema at the backend is
type Subscription{
newMessage(chatRoom: ID!): String!
}
resolver is
const { pubsub } = require("../helper");
const { withFilter } = require("graphql-yoga");
module.exports = {
Subscription: {
newMessage: {
subscribe: withFilter(
() => pubsub.asyncIterator("newMessage"),
(payload, variables) => {
console.log(payload.query, variables, "HALO");
return payload.chatRoom === variables.chatRoom;
}
),
},
},
};
But when I pass the query like below,with no variables to useSubscription hook.Then it works
const SUB_NEW_MSG = gql`
subscription SUB_NEW_MSG
{
newMessage(chatRoom:"608851227be4796a8463607a")
}`;
What should I do?Are there any workarounds?
Change your query to this, and test it.
const SUB_NEW_MSG = gql`
subscription SUB_NEW_MSG($chatRoom: String!) {
newMessage(chatRoom: $chatRoom)
}
`;

Return data from custom Hook calling a graphql query

I am new to graphql and react.. Here , I have following method,
export const useName = (isRequest: boolean) => {
const {
nav: { id, idme }
} = stores
if (buyingSession) {
const { data, loading,error}
= usegroup(id, {
fetchPolicy: 'cache-and-network'
})
} else {
const {data} = usesingle(idme)
}
return data;
}
//This function should return a string which will be in data object.But I am getting confused over here because its a query and it takes time so it returns undefined but when I checked in the network it gives response as well.
export const useme = (id: string) => {
return useQuery(GET_ME, {
fetchPolicy: "cache-first",
skip: !id,
variables: {
id: id
}
}
In another component , I am calling ,
const data = useName(true)
So, this is the call which actually calls the graphql query. Now , when I am getting data it gets undefined.
How do resolve this issue ?

Why are Results logging as undefined after a GraphQL Mutation?

In one of my components within a redux-form onSubmit, I have the following:
const result = await helloSignup(values);
console.log(result);
helloSignup is mutating the database as expected but the const result is currently be logged as undefined
Why?
My HOC/mutation helloSignup:
export const HELLO_SIGNUP_MUTATION = gql`
mutation (
$email: String!
$code: String!
) {
signup(authProvider: {
emailAndCode: {
email: $email
code: $code
}
}) {
token
user {
id
}
}
}
`;
export default graphql(
HELLO_SIGNUP_MUTATION,
{
props: ({ mutate }) => ({
emailAndCodeSignup: async (variables) => {
const { data } = await mutate({ variables });
const { token } = data.signup;
},
}),
}
);
Using GraphiQL, I can see that my graphql mutation, returns the desired results:
{
"data": {
"signup": {
"token": "xxx",
"user": {
"id": "16"
}
}
}
}
If GraphiQL is getting the desired results after mutating, why isn't the result being console logged above?
React-Apollo provides a HOC for client side queries and mutations called withApollo.
This signature is something like this:
withApollo(MyForm)
https://www.apollographql.com/docs/react/basics/setup.html#withApollo
which adds a prop of 'client' to the MyForm component. On form submission, you'd want to access this prop, and call the mutation from there. So in your form submit handler youd end up with something like this:
https://www.apollographql.com/docs/react/basics/mutations.html#basics
onSubmit() {
const { client } = this.props
const options = {} // your mutation options
// mutations ands queries return promises,
// so you must wait for their completion before accessing data
client.mutate(
HELLO_SIGNUP_MUTATION,
options
).then(({ data }) => (
console.log('got data', data);
)
}
}
Where data should be whats coming back from the API

Resources