How can I run a query only one time when the page loads?

I am trying to create a record of a session when the page loads so I can gather user metrics. Initially I thought that I could create a state variable (true | false) Then in a if statement I check if the state is false run my query then set the state to ture.
const [query_ran, set_query_ran] = useState(false);
if (!query_ran) {
const { data, isLoading } = api.session.add_session.useQuery();
set_query_ran(true);
}
const [query_ran, set_query_ran] = useState(false);
if (!query_ran) {
const { data, isLoading } = api.session.add_session.useQuery();
set_query_ran(true);
}
When I try this I get an error: Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement. When I run the query outside of the if block anytime the component remounts a new session record is created in my database. My goal is to create a session when the page loads, get the id of the new session added to my database and use that ID to update the session periodically as the user interacts with my application. Can I please get some guidance on how to do this? As some extra context when I try to use my query in a useEffect block It errors out saying that I cant run a hook inside a hook.
Solution:
I am trying to create a record of a session when the page loads so I can gather user metrics. Initially I thought that I could create a state variable (true | false) Then in a if statement I check if the state is false run my query then set the state to ture. ...
Jump to solution
37 Replies
Brendonovich
Brendonovich16mo ago
You're adding data to your DB, so you should be using a mutation.
const addSession = api.session.add_session.useMutation();

useEffect(() => {
addSession.mutate();
}, [])
const addSession = api.session.add_session.useMutation();

useEffect(() => {
addSession.mutate();
}, [])
If a procedure isn't designed to be re-ran at any arbitrary time, it most likely shouldn't be a query
centelle
centelle16mo ago
maybe refetchOnWindowFocus: false on useQuery can help
Brendonovich
Brendonovich16mo ago
Also you could run the query in useEffect, you just can't use the hook, you need to use the client directly via api.useContext() refetchOnWindowFocus might do the job but IMO it's a bandaid fix
ideceddy
ideceddy16mo ago
Thanks Moving over to a mutation is what I needed to get this to work. But I don't see a way to get the data returned from the mutation.
const [web_session, set_session] = useState();
const add_session = api.session.add_session.useMutation();
useEffect(() => {
const data = add_session.mutate();
set_session(data);
}, []);
console.log(web_session);
const [web_session, set_session] = useState();
const add_session = api.session.add_session.useMutation();
useEffect(() => {
const data = add_session.mutate();
set_session(data);
}, []);
console.log(web_session);
I even tired to create a async function to wait for the promise returned. All I ever see is undefined.
const [web_session, set_session] = useState();
const add_session = api.session.add_session.useMutation();
useEffect(() => {

const fetch_data = async () => {
const data = await add_session.mutate();
return data;
}
set_session(fetch_data();
}, []);
const [web_session, set_session] = useState();
const add_session = api.session.add_session.useMutation();
useEffect(() => {

const fetch_data = async () => {
const data = await add_session.mutate();
return data;
}
set_session(fetch_data();
}, []);
When I look at the logging that trpc ( I think ) returns I can see its returning the data at the end of my session router. return {id: create_session.id } But I get nothing back from the mutation.
Brendonovich
Brendonovich16mo ago
Oh, mutate doesn't use async. You can either provide it with onSuccess callbacks etc, or use mutateAsync which will work fine in your async function useMutation does return a data field though, you may as well use that rather than a separate state
ideceddy
ideceddy16mo ago
I tired to get the return object data from the useMutation but I must have some gaps in my knowledge.
const { mutate, data } = api.session.add_session.useMutation();
useEffect(() => {
mutate();
}, []);
set_session(data);
const { mutate, data } = api.session.add_session.useMutation();
useEffect(() => {
mutate();
}, []);
set_session(data);
What I ended up with was the onSuccess method and that did the trick.
const [web_session, set_session] = useState();
const add_session = api.session.add_session.useMutation();
useEffect(() => {
add_session.mutate(null, {
onSuccess: (data) => {
set_session(data['id']);
}
});
}, []);
const [web_session, set_session] = useState();
const add_session = api.session.add_session.useMutation();
useEffect(() => {
add_session.mutate(null, {
onSuccess: (data) => {
set_session(data['id']);
}
});
}, []);
I'll mark this one as solved 😄 Thanks for all the help ❤️
Brendonovich
Brendonovich16mo ago
In the first example, why do you still call set_session? data has everything you need already inside it
ideceddy
ideceddy16mo ago
Oh right that was the issue 😄
const { mutate, data } = api.session.add_session.useMutation();
useEffect(() => {
mutate();
}, []);
console.log(data);
const { mutate, data } = api.session.add_session.useMutation();
useEffect(() => {
mutate();
}, []);
console.log(data);
Brendonovich
Brendonovich16mo ago
ayyy nice
ideceddy
ideceddy16mo ago
I guess the state was not updated yet. its 3AM here :p
Brendonovich
Brendonovich16mo ago
also do future you a favour and don't destructure the useMutation
ideceddy
ideceddy16mo ago
Like this? I see that destructing in the chirp app but it makes sense if I am going to do more mutations.
const add_session = api.session.add_session.useMutation();
useEffect(() => {
add_session.mutate();
}, []);
console.log(add_session.data);
const add_session = api.session.add_session.useMutation();
useEffect(() => {
add_session.mutate();
}, []);
console.log(add_session.data);
Brendonovich
Brendonovich16mo ago
oh no does theo destructure nooooooo theo is cringe all my homies hate destructuring w/ tanstack
ideceddy
ideceddy16mo ago
const { mutate, isLoading: isPosting } = api.posts.create.useMutation({
onSuccess: () => {
setInput("");
void ctx.posts.getAll.invalidate();
},
onError: (e) => {
const errorMessage = e.data?.zodError?.fieldErrors.content;
if (errorMessage && errorMessage[0]) {
toast.error(errorMessage[0]);
} else {
toast.error("Failed to post! Please try again later.");
}
},
});
const { mutate, isLoading: isPosting } = api.posts.create.useMutation({
onSuccess: () => {
setInput("");
void ctx.posts.getAll.invalidate();
},
onError: (e) => {
const errorMessage = e.data?.zodError?.fieldErrors.content;
if (errorMessage && errorMessage[0]) {
toast.error(errorMessage[0]);
} else {
toast.error("Failed to post! Please try again later.");
}
},
});
Brendonovich
Brendonovich16mo ago
sadge
Want results from more Discord servers?
Add your server