6.2 KiB
This guide provides information about working with React Server Components in your Hydrogen app.
Note: React Server Components are currently in Alpha. However, Hydrogen includes a built-in layer of abstraction that provides stability, regardless of the state of React Server Components.
Fetching data on the server
All data fetching happens on the server and is never exposed to the client, unless you explicitly fetch data in a client component.
Hydrogen provides the following ways to fetch data from server components:
useShopQuery
: A hook that allows you to make server-only GraphQL queries to the Storefront API.useQuery
: A simple wrapper aroundfetch
that supports Suspense. You can use this function to call any third-party APIs.
Accessing Hydrogen components from client components
Because of the way tree-shaking works in Vite, avoid importing server components when referencing Hydrogen client components in one of your client components.
Hydrogen provides a special @shopify/hydrogen/client
module to reference components that are safe to use within client components. You should use this import path when writing your client components.
Sharing state
between client and server
Note: The functionality described in this section is unique to Hydrogen's React Server Components implementation.
Hydrogen provides a useServerState()
hook with a setServerState()
helper function, which allows components to paginate within collections, programmatically switch routes, or do anything that requires new data from the server.
Sharing state information between the client and server is important for common tasks, like page
routing. The following diagram shows how the page
state is shared between the client and server:
-
App.server.jsx
relies on thepage
state to choose the correct route to render. To change routes, the client updates thepage
state:{% codeblock file, filename: 'ProductDetails.client.jsx' %}
useEffect(() => { setServerState('page', location.pathname); }, [location.pathname, setServerState]);
{% endcodeblock %}
-
The
page
state is sent to the server. This happens through auseServerResponse
fetch call. It's a special server endpoint called/react
which acceptsstate
as a query parameter. -
The
/react
endpoint returns the wire representation for the new state. -
The state is partially hydrated (made interactive) and rendered into the DOM, similar to how the initial page was made interactive.
Hydrogen uses
/react
for routing, but also for any other state that needs to be synced to the server.
Using Context
in React Server Components
Note: The functionality described in this section is unique to Hydrogen's React Server Components implementation and will change when server context is implemented upstream in React.
React developers commonly use Context
to share state among many different components in a render tree, without having to drill props down to each individual component.
Server context support is on the React team's roadmap, but it is not yet implemented. In order to share context between server components and client components, Hydrogen provides a workaround mechanism.
Provider
components
Any client component with a name that ends in Provider
receives special treatment during server-rendering and client hydration. This allows server components to share context during the server-side rendering and makes sure that the context is initialized as a client component on the client.
Rules
The following rules apply to Provider
components:
- You can't fetch server-only data from within
Provider
components. Instead, fetch data within server components and pass the data as props to theProvider
. - You can pass props to the
Provider
from server components, but they must be JSON-serializable. - You need to split
Context
andProvider
into separate files due to the way that components are dynamically loaded on the client.
Example
The following example shows the implementation of a Provider
component:
{% codeblock file, filename: 'CartContext.client.jsx' %}
// This must be a separate client component from your special `Provider` component.
const CartAppContext = createContext();
export default CartAppContext;
export function useCartContext() {
const context = useContext(CartAppContext);
if (!context) {
throw new Error('No cart context found');
}
return context;
}
{% endcodeblock %}
{% codeblock file, filename: 'CartProvider.client.jsx' %}
import {CartContext} from './CartContext.client';
export default function CartProvider({items, children}) {
const value = {
items,
// ...
};
return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
}
{% endcodeblock %}
{% codeblock file, filename: 'App.server.jsx' %}
import CartProvider from './CartProvider.client';
export default function App() {
const {data} = useShopQuery({query: QUERY});
return (
<CartProvider items={data.items}>
<p>Your app here</p>
</CartProvider>
);
}
{% endcodeblock %}
Next steps
- Learn how to manage the state on the server as you're building your Hydrogen app.
- Get familiar with the file-based routing system that Hydrogen uses.
- Learn how the page server component receives props, which includes custom versions of
request
andresponse
.