How do I set the default useState value of a trpc call?

EDIT: Sorry apparently I can't rename the title. I meant to say: 'How do I set a default useState value to something that came from a trpc call' Hi folks, so I need some help with my component It's a simple team switcher. I need help understanding a few things. I have two main trpc endpoints: getAllForLoggedUser and switchActiveWorkspace. one thing: whenever I am reloading this component fresh new, I am not being able to set the default value of the useState call. The default value is not being set. How can I make it so it sets the default value that came from the trpc call
export default function TeamSwitcher({ className }: TeamSwitcherProps) {
const ctx = api.useContext();
const { data: session } = useSession();

const { data: workspaces } = api.workspace.getAllForLoggedUser.useQuery(
undefined,
{
enabled: session?.user !== undefined,
}
);

const { mutateAsync } = api.user.switchActiveWorkspace.useMutation({
onSuccess: () => {
void ctx.workspace.getAllForLoggedUser.invalidate();
},
});

const [selectedWS, setSelectedWS] = React.useState<Workspace>({
id: session?.user?.activeWorkspaceId || "",
name:
workspaces?.find((w) => w.id === session?.user?.activeWorkspaceId)
?.name || "", //This was supposed to be working 🥲
});

return (
{/*tsx Code.
At some point there is a mapping of the workspaces array and on each item there is a onSelect like this
onSelect={() => {
setSelectedWS({
id: ws.id,
name: ws.name,
});
setOpen(false);
void mutateAsync({ workspaceId: ws.id });
}}
*/}
)
}
export default function TeamSwitcher({ className }: TeamSwitcherProps) {
const ctx = api.useContext();
const { data: session } = useSession();

const { data: workspaces } = api.workspace.getAllForLoggedUser.useQuery(
undefined,
{
enabled: session?.user !== undefined,
}
);

const { mutateAsync } = api.user.switchActiveWorkspace.useMutation({
onSuccess: () => {
void ctx.workspace.getAllForLoggedUser.invalidate();
},
});

const [selectedWS, setSelectedWS] = React.useState<Workspace>({
id: session?.user?.activeWorkspaceId || "",
name:
workspaces?.find((w) => w.id === session?.user?.activeWorkspaceId)
?.name || "", //This was supposed to be working 🥲
});

return (
{/*tsx Code.
At some point there is a mapping of the workspaces array and on each item there is a onSelect like this
onSelect={() => {
setSelectedWS({
id: ws.id,
name: ws.name,
});
setOpen(false);
void mutateAsync({ workspaceId: ws.id });
}}
*/}
)
}
7 Replies
GBianchi
GBianchi14mo ago
Here's the full code if needed
Neto
Neto14mo ago
put the useState above the queries onSuccess of the query, update the state
export default function TeamSwitcher({ className }: TeamSwitcherProps) {
const ctx = api.useContext();
const { data: session } = useSession();

const [selectedWS, setSelectedWS] = React.useState<some_type>({
id: session?.user?.activeWorkspaceId || "",
name:
workspaces?.find((w) => w.id === session?.user?.activeWorkspaceId)
?.name || "", //This was supposed to be working 🥲
});


const { data: workspaces } = api.workspace.getAllForLoggedUser.useQuery(
undefined,
{
enabled: session?.user !== undefined,
onSuccess: (data) => {
const newSelectedWS = some_logic_goes_where
setSelectedWS(newSelectedWS)
}
}
);

const { mutateAsync } = api.user.switchActiveWorkspace.useMutation({
onSuccess: () => {
void ctx.workspace.getAllForLoggedUser.invalidate();
},
});


return (
<></>
)
}
export default function TeamSwitcher({ className }: TeamSwitcherProps) {
const ctx = api.useContext();
const { data: session } = useSession();

const [selectedWS, setSelectedWS] = React.useState<some_type>({
id: session?.user?.activeWorkspaceId || "",
name:
workspaces?.find((w) => w.id === session?.user?.activeWorkspaceId)
?.name || "", //This was supposed to be working 🥲
});


const { data: workspaces } = api.workspace.getAllForLoggedUser.useQuery(
undefined,
{
enabled: session?.user !== undefined,
onSuccess: (data) => {
const newSelectedWS = some_logic_goes_where
setSelectedWS(newSelectedWS)
}
}
);

const { mutateAsync } = api.user.switchActiveWorkspace.useMutation({
onSuccess: () => {
void ctx.workspace.getAllForLoggedUser.invalidate();
},
});


return (
<></>
)
}
GBianchi
GBianchi14mo ago
@Neto But this way, workspace (where the useState is invoked) will be used before it's being defined. OOh I see what you mean
Neto
Neto14mo ago
if the state is derived from the query you can make a "blank" state and update when the query finishes
GBianchi
GBianchi14mo ago
This fixed it!! Thank you so much ❤️
whatplan
whatplan14mo ago
while this does work its probably not ideal: https://tkdodo.eu/blog/breaking-react-querys-api-on-purpose
Breaking React Query's API on purpose
Why good API design matters, even if it means breaking existing APIs in the face of resistance.