Hi, First Post, Sharing a pattern I've found for RSC to ClientSide state

Hi, anyone else stumble upon this pattern for having the server state initially available when a Client Component loads, and then overwriting it with reactivity latter? I use $state with $ to denote $erver State, to keep it visually separate from client states. Seems like I have been able to have the best of both worlds with this method, no rerender flicker nor skeleton loader needed. But there's got to be a downside or something that I haven't encountered yet. Trying to poke holes in this approach to make sure it's sound before I use it all over the place. Any hole pokers out there? Thanks message was too long, replying with code ....
1 Reply
alphaβiota
alphaβiota5mo ago
// src/components/ui/navigation/user-pfp-icon.tsx

"use client";

import { toggleUserMenu } from "@/src/store/slice/layout";
import store, { RootState } from "@/src/store/store";
import { useSelector } from "react-redux";
import { ClientFcStoreProvider } from "../../client-fc-store-wrap";
import { AvatarThumbnail } from "../profile/AvatarThumbnail";
import { twMerge } from "tailwind-merge";
import { X } from 'lucide-react';
import Button from "../button-alt";
import { useRouter } from "next/navigation";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";

const UserPfpIcon_ = ({ $state }: any): JSX.Element =>
{
const layoutState = useSelector((state: RootState) => state.layout);
const authState = useSelector((state: RootState) => state.auth);

const router = useRouter();
const clientPathname = usePathname();

const [pathname, setPathname] = useState<string>($state.layout.pathname);
useEffect(() =>
{
setPathname(clientPathname)
}, [clientPathname]);

return (
<>
{pathname !== "/auth" &&
<Button
intent="translucent"
size="small"
extendClassName='w-[34px] h-[34px] font-bold p-0 m-0'
id="buttonNavUserMenu"
onClick={async () =>
{
if (authState.isLoggedIn) { store.dispatch(toggleUserMenu()) }
else router.push("/auth")
return true
}}
>
<div
className={twMerge("drop-shadow-[0px_2px_1px_#00000033] rounded-full", "bg-[var(--icon-bg)]")}>
{layoutState.userMenuOpen ? <X /> :
<AvatarThumbnail user={authState?.user || $state?.auth?.user} />}
</div>

</Button>
}
</>
)
};

export const UserPfpIcon = ({ $state }: any) => <ClientFcStoreProvider ><UserPfpIcon_ $state={$state} /></ClientFcStoreProvider>
// src/components/ui/navigation/user-pfp-icon.tsx

"use client";

import { toggleUserMenu } from "@/src/store/slice/layout";
import store, { RootState } from "@/src/store/store";
import { useSelector } from "react-redux";
import { ClientFcStoreProvider } from "../../client-fc-store-wrap";
import { AvatarThumbnail } from "../profile/AvatarThumbnail";
import { twMerge } from "tailwind-merge";
import { X } from 'lucide-react';
import Button from "../button-alt";
import { useRouter } from "next/navigation";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";

const UserPfpIcon_ = ({ $state }: any): JSX.Element =>
{
const layoutState = useSelector((state: RootState) => state.layout);
const authState = useSelector((state: RootState) => state.auth);

const router = useRouter();
const clientPathname = usePathname();

const [pathname, setPathname] = useState<string>($state.layout.pathname);
useEffect(() =>
{
setPathname(clientPathname)
}, [clientPathname]);

return (
<>
{pathname !== "/auth" &&
<Button
intent="translucent"
size="small"
extendClassName='w-[34px] h-[34px] font-bold p-0 m-0'
id="buttonNavUserMenu"
onClick={async () =>
{
if (authState.isLoggedIn) { store.dispatch(toggleUserMenu()) }
else router.push("/auth")
return true
}}
>
<div
className={twMerge("drop-shadow-[0px_2px_1px_#00000033] rounded-full", "bg-[var(--icon-bg)]")}>
{layoutState.userMenuOpen ? <X /> :
<AvatarThumbnail user={authState?.user || $state?.auth?.user} />}
</div>

</Button>
}
</>
)
};

export const UserPfpIcon = ({ $state }: any) => <ClientFcStoreProvider ><UserPfpIcon_ $state={$state} /></ClientFcStoreProvider>
Want results from more Discord servers?
Add your server