I have the following code but it renders the cookieData undefined on the first render and query, so the query doesn't get the cookie and it fails authetication. Any way to make the query wait for the call to the cookie api to come back before running.
const { data: cookieData, error: cookieError } = useSWR(
"/api/cookie",
fetcher
);
console.log(cookieData);
var test = `Bearer ${cookieData}`;
const { loading, error, data } = useQuery(FORMS, {
context: {
headers: {
authorization: test,
},
},
});
UPDATE: I ended up using lazy query for the above, but I will try skip as well, but I have been trying to implement skip on this mutation now and it says the id is undefined, it consoles on the page but is undfined first a few times.
const addFormClicked = async (data) => {
//console.log(data);
const res = await createForm({
variables: {
name: data.name,
user: user.id,
},
skip: !user.id,
});
console.log(res);
Router.push(`/formBuild/${res.data.createForm._id}`);
};
Here's the whole code for context
import { useMutation, gql } from "@apollo/client";
import Layout from "../components/Layout";
import { useForm } from "react-hook-form";
import { useRouter } from "next/router";
import { FORMS } from "../components/Layout";
import useSWR from "swr";
import { useState } from "react";
const ADD_FORM = gql`
mutation AddForm($name: String!, $id: ID!) {
createForm(data: { name: $name, user: { connect: $id } }) {
name
_id
}
}
`;
const fetcher = (url) => fetch(url).then((r) => r.json());
export default function AddForm() {
const { data: user } = useSWR("/api/user"); // add
const { data: cookieData, error: cookieError } = useSWR(
"/api/cookie",
fetcher
);
var test = `Bearer ${cookieData}`;
const Router = useRouter();
const [
createForm,
{
data: createFormData,
error: createFormError,
loading: createFormLoading,
},
] = useMutation(ADD_FORM, {
refetchQueries: [{ query: FORMS }],
context: {
headers: {
authorization: test,
},
},
});
const addFormClicked = async (data) => {
//console.log(data);
const res = await createForm({
variables: {
name: data.name,
user: user.id,
},
skip: !user.id,
});
console.log(res);
Router.push(`/formBuild/${res.data.createForm._id}`);
};
const { register, handleSubmit, errors, reset } = useForm();
if (createFormLoading) return <p>Loading</p>;
if (createFormError) return <p>Error: {createFormError.message}</p>;
//console.log(createFormData);
return (
<Layout>
<form onSubmit={handleSubmit(addFormClicked)}>
<h1>Form Name</h1>
<input type="text" name="name" ref={register()} />
<button type="submit">Add Form</button>
</form>
</Layout>
);
}
UPDATE: The user needed to be id, seen below
const addFormClicked = async (data) => {
//console.log(data);
const res = await createForm({
variables: {
name: data.name,
id: user.id, //NOT user:user.id BUT id:user.id
},
skip: !user.id,
});
console.log(res);
Router.push(`/formBuild/${res.data.createForm._id}`);
};
The user
variable will be undefined
while the query is in a loading
state. Same with cookieData
. There's no skip
option available in useMutation
since it does not automatically execute the mutation when the component renders.
A simple solution would be to render the form if only if user
and cookieData
exist. This way, you can know for sure the user id and token will be available when the form gets submitted.
// Add `userError` to use in combination with `user` to check if the query is loading
const { data: user, error: userError } = useSWR('/api/user', userFetcher)
const [
createForm,
{ data: createFormData, error: createFormError, loading: createFormLoading },
] = useMutation(ADD_FORM, {
refetchQueries: [{ query: FORMS }],
})
const addFormClicked = async (data) => {
const res = await createForm({
context: {
headers: {
authorization: `Bearer ${cookieData}`,
},
},
variables: {
name: data.name,
user: user.id,
},
})
Router.push(`/formBuild/${res.data.createForm._id}`)
}
if (userError || cookieError) {
return <div>Something went wrong</div>
}
if (!user || !cookieData) {
return <div>Loading...</div>
}
// Render form