Continuing the need to have easy context from my other posts, I wanted to find a way to share context on the server as well.
You may have noticed thatuseContext
andcreateContext
do not compile on the server (another millionth reason I love SvelteKit!).
So, there needs to be a way to do this easily in RSC, even though the React Team, who seems to be extremely far away from the actual userbase, decided to depreciate this feature before it was actually implemented.
You can findcreateServerContext
in the latest React as an import, but there is no actualConsumer
like there is in a regular context, so I couldn't get it to work. Supposedly it could be shared on the client and server, but only for small strings. The only actual mention of this is in atweet:
letLang=createServerContext("lang","en");...<Lang.Providervalue={…}>...use(Lang)
Either way, I would have re-written this to work like my other context, so it is a moot point.
I should also add, the second best solution is to use theserver-only-context library (by manvalls) which usescache
under the hood.
Dear React Team (and NextJS Team)
There is a reason there are so many external state libraries for React. The way React works out-of-the-box is terrible and uses too much boilerplate. We love RSC (the people on the React train who won't move to Svelte have no choice) and we love that Vercel wants to add Server Actions, but either of you can fix this problem. No more Context Hell please!
React Team... Let's add signals (or something better) as well please and not worry about memoizing state! Why are you making things hard that don't have to be!!!!? Serious question.
Ok, I digress.
The Solution
So I basically copied thecache
idea from above, but simplified it for my use case with the Map from my other solutions. Thecache
is actually a Map itself, so I believe this is a Map of a Map under the hood.
use-server-provider.tsx
import'server-only';import{cache}from'react';constserverContext=cache(()=>newMap());exportconstuseServerProvider=<T,>(key:string,defaultValue?:T)=>{constglobal=serverContext();if(defaultValue!==undefined){global.set(key,defaultValue);}return[global.get(key),(value:T)=>global.set(key,value)];};
Parent
const[count,setCount]=useServerProvider('count',23);
Child
const[count]=useServerProvider<number>('count');
However, it is worth noting, unlike a reactive component, if you set the component after you define thecount
variable, it won't update unless you grab thecount
variable again. One way to fix this is to use avalue
object key like in a signal:
import'server-only';import{cache}from'react';constserverContext=cache(()=>newMap());exportconstuseServerProvider=<T,>(key:string,defaultValue?:T)=>{constglobal=serverContext();if(defaultValue!==undefined){global.set(key,defaultValue);}return{getvalue(){returnglobal.get(key)},setvalue(v:T){global.set(key,v);}}};
Then you could do this:
Parent
constcount=useServerProvider('count',23);count.value=27;
Child
exportdefaultfunctionTestChild(){constcount=useServerProvider<number>('count');return(<p>Child:{count.value}</p>)}
Nevertheless, on a server you shouldn't care about any of this... so the original react-like way still stands.
Probably the last article in this series... probably...
J
Getting back to rebuildingcode.build
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse