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
Brendonovich2y 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
centelle2y ago
maybe refetchOnWindowFocus: false on useQuery can help
Brendonovich
Brendonovich2y 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
ideceddyOP2y 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
Brendonovich2y 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
ideceddyOP2y 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
Brendonovich2y ago
In the first example, why do you still call set_session? data has everything you need already inside it
ideceddy
ideceddyOP2y 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
Brendonovich2y ago
ayyy nice
ideceddy
ideceddyOP2y ago
I guess the state was not updated yet. its 3AM here :p
Brendonovich
Brendonovich2y ago
also do future you a favour and don't destructure the useMutation
ideceddy
ideceddyOP2y 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
Brendonovich2y ago
oh no does theo destructure nooooooo theo is cringe all my homies hate destructuring w/ tanstack
ideceddy
ideceddyOP2y 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
Brendonovich2y ago
sadge
ideceddy
ideceddyOP2y ago
TBF it looks cool and the . is so far on the keyboard.
Brendonovich
Brendonovich2y ago
i hate isLoading: isPosting what keyboard layout are u using haha . for me is one down from my ring finger
ideceddy
ideceddyOP2y ago
I am a goblen and type with one hand at 3AM
Brendonovich
Brendonovich2y ago
lmaooooo fair
ideceddy
ideceddyOP2y ago
Thanks Again you are the best 😄
Brendonovich
Brendonovich2y ago
happy to help!
Lopen
Lopen2y ago
I don't think this will run You can't mutate or query in a useEffect
Brendonovich
Brendonovich2y ago
?? sure u can we use useEffect for firing our analytics mutations
Lopen
Lopen2y ago
Trpc procedures?
Brendonovich
Brendonovich2y ago
you can't useQuery or useMutation inside a useEffect, but you can mutate and refetch rspc, basically rust trpc it's all tanstack
Lopen
Lopen2y ago
But useMutation is for the backend and useEffect is client based
Brendonovich
Brendonovich2y ago
i don't get your point
ideceddy
ideceddyOP2y ago
Works on local and the edge 🙂
Brendonovich
Brendonovich2y ago
useEffect is just a mechanism for running code in response to a state change triggering a mutation in there is fine
Lopen
Lopen2y ago
Maybe things has changed though
Brendonovich
Brendonovich2y ago
it's not useMutation exactly but it's the same idea
Lopen
Lopen2y ago
I remember trying this a while ago and TypeScript was yelling at me
ideceddy
ideceddyOP2y ago
It was yelling at me for useMutation but not mutate.
Brendonovich
Brendonovich2y ago
yea i have a feeling you may have been using useMutation in the useEffect in which case you can't bc it breaks the rules of hooks
Lopen
Lopen2y ago
Oh, i see your point now Your talking of the mutate from the destructed response of useMutation, not .mutation on the backend
Brendonovich
Brendonovich2y ago
ye ye
destructed response
better not be destructured hehe
Want results from more Discord servers?
Add your server