Not understanding best practices

Hey, I am having a bit of trouble with my app. Here is the list: 1. Any time I do any basic crud operations my entire page reloads without calling router refresh or revalidatepath (trpc fetches again on any db write) 2. I have a component where I query data and pass that data into two separate client components, one that adds an issue, and one that displays the issues. When an issue is added I don't want to router.refresh every single time but I may have to in order to get the other client component to update. 3. Realtime functionality. This is a multi-tenancy system and I need to be able to add realtime funcationality to prevent race conditions when editing. Websockets for trpc seems very complicated when I look at it, and pusher channels don't work in trpc.
8 Replies
Crim
CrimOP10mo ago
Code for problem #2:
export default async function Page({
params,
}: {
params: { endeavorId: string; teamId: string };
}) {
const endevInfo = await api.endeavor.getEndeavorInfo.query({
endeavorName: params.endeavorId,
teamId: params.teamId,
});
return (
<div className="flex min-h-screen w-full flex-col overflow-hidden">
<div className="flex min-h-[60px] items-center justify-between gap-3 border-b px-4">
<span className="font-inter text-sm tracking-wide text-foreground/90">
Your issues
</span>
<div className="flex items-center gap-4">
<div className="flex">
<Button
variant={"outline"}
size={"icon"}
className="flex rounded-br-none rounded-tr-none border-r-0"
>
<Rows3 className="h-4 w-4" />
</Button>
<Button
variant={"outline"}
size={"icon"}
className="flex rounded-bl-none rounded-tl-none"
>
<GripVertical className="h-4 w-4" />
</Button>
</div>
<AddIssue endeavor={endevInfo} />
</div>
</div>
<div className="flex h-full flex-col">
{endevInfo[0]?.issues.length! > 0 ? (
<IssueDisplay endeavor={endevInfo} />
) : (
<div className="flex h-full items-center justify-center">
<Card className="w-1/6 px-2">
<CardHeader className="flex flex-row items-center gap-2 font-inter text-xl font-semibold">
No issues found.
</CardHeader>
<CardContent className="text-muted-foreground">
You have no issues. To create a new issue press CTRL + I, or
press the + in the top left corner of the page.
</CardContent>
</Card>
</div>
)}
</div>
</div>
);
}
export default async function Page({
params,
}: {
params: { endeavorId: string; teamId: string };
}) {
const endevInfo = await api.endeavor.getEndeavorInfo.query({
endeavorName: params.endeavorId,
teamId: params.teamId,
});
return (
<div className="flex min-h-screen w-full flex-col overflow-hidden">
<div className="flex min-h-[60px] items-center justify-between gap-3 border-b px-4">
<span className="font-inter text-sm tracking-wide text-foreground/90">
Your issues
</span>
<div className="flex items-center gap-4">
<div className="flex">
<Button
variant={"outline"}
size={"icon"}
className="flex rounded-br-none rounded-tr-none border-r-0"
>
<Rows3 className="h-4 w-4" />
</Button>
<Button
variant={"outline"}
size={"icon"}
className="flex rounded-bl-none rounded-tl-none"
>
<GripVertical className="h-4 w-4" />
</Button>
</div>
<AddIssue endeavor={endevInfo} />
</div>
</div>
<div className="flex h-full flex-col">
{endevInfo[0]?.issues.length! > 0 ? (
<IssueDisplay endeavor={endevInfo} />
) : (
<div className="flex h-full items-center justify-center">
<Card className="w-1/6 px-2">
<CardHeader className="flex flex-row items-center gap-2 font-inter text-xl font-semibold">
No issues found.
</CardHeader>
<CardContent className="text-muted-foreground">
You have no issues. To create a new issue press CTRL + I, or
press the + in the top left corner of the page.
</CardContent>
</Card>
</div>
)}
</div>
</div>
);
}
Y7YA
Y7YA10mo ago
Are you using any forms?
Crim
CrimOP10mo ago
yeah, I will remove the unnecessary parts of the code for you:
export function AddIssue(endeavor: { endeavor: EndeavorWithObjects[] }) {
const [charCount, setCharCount] = useState(0);
const [titleInput, setTitleInput] = useState("");
const [description, setDescription] = useState("");
const [currentLabel, setLabel] = useState<string>("");
const [status, setStatus] = useState<Status>(Status.Not_Started);
const [priority, setPriority] = useState<Priority>(Priority.None);
const [open, setOpen] = useState(false);
const addIssue = api.endeavor.createIssue.useMutation({
onSuccess: (e) => {
setOpen(false);
setTitleInput("");
setDescription("");
setStatus(Status.Not_Started);
setPriority(Priority.None);
toast("You have created a new issue!", {
description: "Click on it to maximize.",
});
},
});

<div className="flex flex-col">
<Input
className="rounded-none border-0 border-b font-inter shadow-none focus- visible:ring-0"
maxLength={40}
value={titleInput}
onChange={(e) => setTitleInput(e.target.value)}
placeholder={"Issue title"}
/>
<Textarea
maxLength={250}
placeholder="Enter issue description here."
className="h-40 resize-none border-none shadow-none"
onChange={(e) => {
setCharCount(e.target.value.length);
setDescription(e.target.value);
}}
/>
</div>
export function AddIssue(endeavor: { endeavor: EndeavorWithObjects[] }) {
const [charCount, setCharCount] = useState(0);
const [titleInput, setTitleInput] = useState("");
const [description, setDescription] = useState("");
const [currentLabel, setLabel] = useState<string>("");
const [status, setStatus] = useState<Status>(Status.Not_Started);
const [priority, setPriority] = useState<Priority>(Priority.None);
const [open, setOpen] = useState(false);
const addIssue = api.endeavor.createIssue.useMutation({
onSuccess: (e) => {
setOpen(false);
setTitleInput("");
setDescription("");
setStatus(Status.Not_Started);
setPriority(Priority.None);
toast("You have created a new issue!", {
description: "Click on it to maximize.",
});
},
});

<div className="flex flex-col">
<Input
className="rounded-none border-0 border-b font-inter shadow-none focus- visible:ring-0"
maxLength={40}
value={titleInput}
onChange={(e) => setTitleInput(e.target.value)}
placeholder={"Issue title"}
/>
<Textarea
maxLength={250}
placeholder="Enter issue description here."
className="h-40 resize-none border-none shadow-none"
onChange={(e) => {
setCharCount(e.target.value.length);
setDescription(e.target.value);
}}
/>
</div>
<div className="flex gap-3">
<span
className={cn(
"flex items-center font-jetbrains text-sm",
charCount >= 150 && charCount < 200
? "text-orange-500"
: charCount >= 200
? "text-red-500"
: null,
)}
>
{charCount}/250
</span>
<Button
onClick={() =>
addIssue.mutate({
issueName: titleInput,
issueDesc: description,
endeavorName: endeavor.endeavor[0]!.name,
teamId: endeavor.endeavor[0]!.team.id,
priority: priority,
status: status,
testIssueLabel: currentLabel,
})
}
size={"sm"}
>
Create issue
</Button>
</div>
<div className="flex gap-3">
<span
className={cn(
"flex items-center font-jetbrains text-sm",
charCount >= 150 && charCount < 200
? "text-orange-500"
: charCount >= 200
? "text-red-500"
: null,
)}
>
{charCount}/250
</span>
<Button
onClick={() =>
addIssue.mutate({
issueName: titleInput,
issueDesc: description,
endeavorName: endeavor.endeavor[0]!.name,
teamId: endeavor.endeavor[0]!.team.id,
priority: priority,
status: status,
testIssueLabel: currentLabel,
})
}
size={"sm"}
>
Create issue
</Button>
</div>
there is more code in between but they are just dropdowns that let you select label status and priority
Y7YA
Y7YA10mo ago
If that button is inside a form you need to specify type="button" otherwise it will reload the page on every click
Crim
CrimOP10mo ago
no there is no form component oh actually you were right thats weird, its not in a form component but still reloading type button fixed that issue
Y7YA
Y7YA10mo ago
strange
Crim
CrimOP10mo ago
do you have any tips on sharing the data between the components?
Y7YA
Y7YA10mo ago
Could use jotai atoms if all the components are going to be sharing 1 state or context if its going to be contained within a reusable group of components
Want results from more Discord servers?
Add your server