Skip to content

Commit

Permalink
Remove useLoaderData from errorElement (#2152)
Browse files Browse the repository at this point in the history
* remove useLoaderData from errorElement and refactor root to use Remix's Layout export

* add changeset

* fix merge missed
  • Loading branch information
michenly committed May 29, 2024
1 parent 97c559b commit e29ecf0
Show file tree
Hide file tree
Showing 28 changed files with 1,025 additions and 1,162 deletions.
73 changes: 73 additions & 0 deletions .changeset/ten-apes-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
'skeleton': patch
'@shopify/cli-hydrogen': patch
---

Refactor root to use [Remix's Layout Export pattern](https://remix.run/docs/en/main/file-conventions/root#layout-export).
This will also fix below error ahead of Single Fetch future flag.

> You cannot `useLoaderData` in an errorElement
The diff below showcase how you can make this refactor in your existing application.

```diff
import {
Outlet,
- useLoaderData,
+ useRouteLoaderData,
} from '@remix-run/react';
-import {Layout} from '~/components/Layout';
+import {PageLayout} from '~/components/PageLayout';

-export default function App() {
+export function Layout({children}: {children?: React.ReactNode}) {
const nonce = useNonce();
- const data = useLoaderData<typeof loader>();
+ const data = useRouteLoaderData<typeof loader>('root');

return (
<html>
...
<body>
- <Layout {...data}>
- <Outlet />
- </Layout>
+ {data? (
+ <PageLayout {...data}>
+ {children}
+ </PageLayout>
+ ) : (
+ children
+ )}
</body>
</html>
);
}

+export default function App() {
+ return <Outlet />;
+}

export function ErrorBoundary() {
const rootData = useLoaderData<typeof loader>();

return (
- <html>
- ...
- <body>
- <Layout {...rootData}>
- <div className="route-error">
- <h1>Error</h1>
- ...
- </div>
- </Layout>
- </body>
- </html>
+ <div className="route-error">
+ <h1>Error</h1>
+ ...
+ </div>
);
}

```
33 changes: 20 additions & 13 deletions examples/b2b/app/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import {Await, NavLink} from '@remix-run/react';
import {Suspense} from 'react';
import type {HeaderQuery} from 'storefrontapi.generated';
import type {LayoutProps} from '~/components/Layout';
import {Await, NavLink} from '@remix-run/react';
import {type CartViewPayload, useAnalytics} from '@shopify/hydrogen';
import type {HeaderQuery, CartApiQueryFragment} from 'storefrontapi.generated';
import {useAside} from '~/components/Aside';
import {type CustomerCompanyLocationConnection} from '~/root';
import {useRootLoaderData} from '~/lib/root-data';
import {useB2BLocation} from './B2BLocationProvider';
import {useAside} from '~/components/Aside';
import {type CartViewPayload, useAnalytics} from '@shopify/hydrogen';

type HeaderProps = Pick<LayoutProps, 'header' | 'cart' | 'isLoggedIn'>;
interface HeaderProps {
header: HeaderQuery;
cart: Promise<CartApiQueryFragment | null>;
isLoggedIn: Promise<boolean>;
publicStoreDomain: string;
}

type Viewport = 'desktop' | 'mobile';

export function Header({header, isLoggedIn, cart}: HeaderProps) {
export function Header({
header,
isLoggedIn,
cart,
publicStoreDomain,
}: HeaderProps) {
const {shop, menu} = header;
return (
<header className="header">
Expand All @@ -23,6 +30,7 @@ export function Header({header, isLoggedIn, cart}: HeaderProps) {
menu={menu}
viewport="desktop"
primaryDomainUrl={header.shop.primaryDomain.url}
publicStoreDomain={publicStoreDomain}
/>
<HeaderCtas isLoggedIn={isLoggedIn} cart={cart} />
</header>
Expand All @@ -33,12 +41,13 @@ export function HeaderMenu({
menu,
primaryDomainUrl,
viewport,
publicStoreDomain,
}: {
menu: HeaderProps['header']['menu'];
primaryDomainUrl: HeaderQuery['shop']['primaryDomain']['url'];
primaryDomainUrl: HeaderProps['header']['shop']['primaryDomain']['url'];
viewport: Viewport;
publicStoreDomain: HeaderProps['publicStoreDomain'];
}) {
const {publicStoreDomain} = useRootLoaderData();
const className = `header-menu-${viewport}`;

function closeAside(event: React.MouseEvent<HTMLAnchorElement>) {
Expand Down Expand Up @@ -85,7 +94,6 @@ export function HeaderMenu({
</NavLink>
);
})}

{/***********************************************/
/********** EXAMPLE UPDATE STARTS ************/}
<ChangeLocation />
Expand Down Expand Up @@ -129,7 +137,6 @@ function HeaderMenuMobileToggle() {

function SearchToggle() {
const {open} = useAside();
const {publish, shop, cart, prevCart} = useAnalytics()
return (
<button className="reset" onClick={() => open('search')}>
Search
Expand Down
74 changes: 74 additions & 0 deletions examples/b2b/app/lib/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export const CART_QUERY_FRAGMENT = `#graphql
name
value
}
# /***********************************************/
# /********** EXAMPLE UPDATE STARTS ************/
quantityRule {
maximum
minimum
Expand All @@ -66,6 +68,8 @@ export const CART_QUERY_FRAGMENT = `#graphql
}
}
}
# /********** EXAMPLE UPDATE END ************/
# /***********************************************/
}
}
}
Expand Down Expand Up @@ -116,3 +120,73 @@ export const CART_QUERY_FRAGMENT = `#graphql
}
}
` as const;

const MENU_FRAGMENT = `#graphql
fragment MenuItem on MenuItem {
id
resourceId
tags
title
type
url
}
fragment ChildMenuItem on MenuItem {
...MenuItem
}
fragment ParentMenuItem on MenuItem {
...MenuItem
items {
...ChildMenuItem
}
}
fragment Menu on Menu {
id
items {
...ParentMenuItem
}
}
` as const;

export const HEADER_QUERY = `#graphql
fragment Shop on Shop {
id
name
description
primaryDomain {
url
}
brand {
logo {
image {
url
}
}
}
}
query Header(
$country: CountryCode
$headerMenuHandle: String!
$language: LanguageCode
) @inContext(language: $language, country: $country) {
shop {
...Shop
}
menu(handle: $headerMenuHandle) {
...Menu
}
}
${MENU_FRAGMENT}
` as const;

export const FOOTER_QUERY = `#graphql
query Footer(
$country: CountryCode
$footerMenuHandle: String!
$language: LanguageCode
) @inContext(language: $language, country: $country) {
menu(handle: $footerMenuHandle) {
...Menu
}
}
${MENU_FRAGMENT}
` as const;
Loading

0 comments on commit e29ecf0

Please sign in to comment.