👨💼 It's kind of annoying to have to send the search
and shipId
props down
through the App
to all our components below. It would be nice if we could
use context to share these values...
🦉 One of the limitations of React Server Components is the lack of support for React Context.
React Server Components can absolutely render components that use context:
async function MyServerComponent() {
return (
<div>
<MyCombobox>
<MyComboboxLabel>Pet Chooser</MyComboboxLabel>
<MyComboboxInput />
</MyCombobox>
</div>
)
}
// assume MyCombobox is a client component that uses context
But they can't use(Context)
themselves.
This is a bummer because another benefit of context is avoiding prop drilling for things like the user object, theme, or localization.
Luckily for us, Node.js has an answer. Again, this isn't a Node.js workshop, but this is a common problem that you'll experience when using RSCs and this is the solution recommended by the React team.
The answer is AsyncLocalStorage
.
Here's a simple example from the docs:
import { AsyncLocalStorage } from 'node:async_hooks'
const userStorage = new AsyncLocalStorage()
// somewhere later in your code
const user = await getUser()
try {
userStorage.run(user, () => {
logUser() // Returns the user object
setTimeout(() => {
logUser() // Logs the user object
}, 200)
throw new Error()
})
} catch (e) {
logUser() // Logs undefined
}
function logUser() {
const user = userStorage.getStore()
console.log({ user })
}
It's a little magical, but the idea is that you can store a value in the
AsyncLocalStorage
and then access it from anywhere in your code, so long as
the async operation was created within the run
callback.
👨💼 Great, thanks Olivia! So what I want you to do is use this to make the
search
and shipId
values available to all components in the tree without
having to pass them down as props.
🐨 First you'll want to create a module to create our async storage object. So let's start by creating and stick this in there:
import { AsyncLocalStorage } from 'node:async_hooks'
export const shipDataStorage = new AsyncLocalStorage()
From there, you can import it in to provide
the search
and shipId
to the rendered components, remove all the prop
drilling from and access the values necessary
from the async storage in
and .