best way to pass props to deeply nested serverside component?
Answered
Peterbald posted this in #help-forum
PeterbaldOP
so I am fetching some data in layout.tsx and there's a route component deeply nested below that I need the data in. Is there a "hack" to pass the prop? (e.g. setting a property on the request object, or in a header)
Answered by riský
however if you just need to store data you can be funny and: https://github.com/manvalls/server-only-context/blob/main/src/index.ts
50 Replies
PeterbaldOP
I figured i can just do this:
seems a bit hacky tho, maybe theres a better way...
const serverState = new Map();
export function setServerState(key: string, value: Object) {
serverState.set(key, value);
}
export function getServerState(key: string) {
return serverState.get(key);
}
export function deleteServerState(key: string) {
serverState.delete(key);
}seems a bit hacky tho, maybe theres a better way...
you should make a "helper" utils file and use react cache to retur the data you wat in both places and then you call it in them and only one db request will occure
but your solution kinda does same thing
Wouldnt this be a candiate for a provider context??
"serverside component"
pass it into the provider from the server component?
we dont need to use client things if all on server
@riský *but your solution kinda does same thing*
PeterbaldOP
ok so apparently my solution stops working when fast refreshed (? not sure why)
does react cache solve this problem? I'm going to try it
Tonkinese
Yes try the react cache approach. But remember that the value can’t be accessed in a client component
PeterbaldOP
yes it has secrets in it... i would hope it cannot be accessed in client
Tonkinese
It can’t so you are safe there.
PeterbaldOP
import { User } from "@/types";
import { cache } from "react";
interface State {
key2: number; // for testing
user: User;
}
type Keys = keyof State;
const state = new Map<Keys, State[Keys]>();
const serverState = cache(() => state);
export function setServerState<K extends Keys>(key: K, value: State[K]) {
const cacheInstance = serverState();
console.log("setting", key, value);
cacheInstance.set(key, value);
}
export function getServerState<K extends Keys>(key: K): State[K] | undefined {
console.log("getting", key, serverState());
const cacheInstance = serverState();
return cacheInstance.get(key) as State[K] | undefined;
}
export function deleteServerState<K extends Keys>(key: K) {
const cacheInstance = serverState();
cacheInstance.delete(key);
}this gives the same behaviour as before
i haven't really found anny examples of using React.cache
so im not sure if this is right
im using it as if it's useMemo without dependencies
the problem:
- when I fast refresh the deeply nested child server component, the Map becomes empty (?)
- when I fast refresh the deeply nested child server component, the Map becomes empty (?)
note that
setServerState is called in a layout.tsxPeterbaldOP
ok i think it's actually not possible to fix this issue with fast refresh
@riský use it like this (ofc the "good way")
PeterbaldOP
fast refresh still makes it undefined for some reason? anyways here's what I tried:
it works initially, but if I edit the nested
// state.ts
const serverState = new Map<Keys, State[Keys]>();
export const cachedState = cache(() => serverState);// nested page.tsx
export default function Page() {
const state = cachedState();
const data = state.get("data");
console.log("server state", data);
return /* ... */;
}// layout.tsx
export default function Layout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const state = cachedState();
state.set("user", sessionUser.user);
return /* ... */;
}it works initially, but if I edit the nested
page.tsx file and trigger a fast refresh, the state becomes undefined again...im suspecting it has something to do with how I import
state.ts and the serverState is definedthat isnt what i meant, just put your fetching alg or smth inside
@riský that isnt what i meant, just put your fetching alg or smth inside
PeterbaldOP
ohhhhh shit
i think this might work
however if you just need to store data you can be funny and: https://github.com/manvalls/server-only-context/blob/main/src/index.ts
Answer
@riský however if you just need to store data you can be funny and: <https://github.com/manvalls/server-only-context/blob/main/src/index.ts>
PeterbaldOP
THIS IS EXACTLY WHAT I WANTED
tysm bro
i love this solution
np i rememberd it was using cache but looked through my huge history to find :)))
PeterbaldOP
can i ask why next.js doesn't have this
natively
like
no one likes prop drilling
me not know
but this is kinda hacky but funny
@riský but this is kinda hacky but funny
PeterbaldOP
is there any downsides?
usually hacky solutoins are
"not best practices"
ok i dont know the legitimacy
but what type of data do you want to share
and why cant you do it in the properly designed cache (ie fetch and do things there to get deduped)
PeterbaldOP
a lot of user data, and it's also streamed
@riský and why cant you do it in the properly designed cache (ie fetch and do things there to get deduped)
PeterbaldOP
i technically can
but this solutions feels right
Note: when navigating on the client side the layout is not re-rendered, so you need to set the context both in the page and in the layout.this is good to know tho