Shopify / hydrogen-v1

React-based framework for building dynamic, Shopify-powered custom storefronts.
https://shopify.github.io/hydrogen-v1/
MIT License
3.75k stars 326 forks source link

[BUG] serverProps is always empty in server components #2077

Open ramiroazar opened 2 years ago

ramiroazar commented 2 years ago

Describe the bug

When using useServerProps in any server components, including routes, serverProps is always empty.

I'm running into this while trying to share data between client and server as described below.

https://shopify.dev/custom-storefronts/hydrogen/framework/work-with-rsc#sharing-data-between-client-and-server

My understanding is that it's recommended to execute requests to Shopify on the server, but not sure how to achieve this if the request relies on client data and the recommended mechanism for sharing data with the server doesn't seem to make it available to server components?

Interestingly, accessing server props from route props like the example below works as expected.

https://shopify.dev/custom-storefronts/hydrogen/framework/server-props#example

Worth noting that using useServerProps in server components also throws the following warning.

Warning: Only ServerContext is supported in Flight.

This is related to Shopify/hydrogen#2042.

To Reproduce

  1. Nest client component inside server component (e.g. <ServerComponent><ClientComponent /></ServerComponent>)
  2. Use setServerProps in client component (e.g. onClick={() => setServerProps('key', 'value')})
  3. Log serverProps in both client and server components (e.g. console.log(serverProps))
  4. Note serverProps returns {key: 'value'} in client component and {} in server component

Expected behaviour

serverProps should return {key: 'value'} instead of {} in the server component, like it does in the client component.

Additional context

ramiroazar commented 1 year ago

After working with this some more, it seems that useServerProps is reserved for client components and that this is intended behaviour.

I think it might be worth calling this out in the useServerProps documentation if that's the case.

Instead of trying to access serverProps within nested server components, the useRequestContext hook can be used within route components to add server props to the context, which can then be accessed by nested server components in the same way.

Apparently request context is an experimental feature, but hopefully this functionality will continue to work, it's super useful.

JaapWeijland commented 1 year ago

@ramiroazar is this still working for you? I'm trying to get the serverProps in a non-route server component, and all I'm getting is an empty object using this hook:

const context = useRequestContext(); console.log('test', context); test [Object: null prototype] {}

The route server component does return the prop that I set using setServerProps.

ramiroazar commented 1 year ago

Yeah, this is still working, @JaapWeijland.

In the route server component that's returning the prop you set using setServerProps, are you then adding that prop to the context (e.g. context.someProp = someProp)?

Just keep in mind that the context from useRequestContext() is empty by default, it doesn't expose serverProps automatically, they have to be added before they're available to other server components.