Skip to content

Commit

Permalink
fix: useProtectedDataQueries isReady value (#197)
Browse files Browse the repository at this point in the history
* More stuff

* Added changeset value
  • Loading branch information
patricklafrance committed Sep 14, 2024
1 parent 1b818ce commit 0c43a84
Show file tree
Hide file tree
Showing 15 changed files with 66 additions and 62 deletions.
5 changes: 5 additions & 0 deletions .changeset/tricky-moons-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@squide/firefly": patch
---

Fix useProtectedDataQueries isReady result value.
2 changes: 1 addition & 1 deletion docs/guides/add-authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ export function RootLayout() {

Finally, assemble everything:

```tsx !#16,20,30-33 host/src/register.tsx
```tsx !#13,16,20,22,30-33 host/src/register.tsx
import { PublicRoutes, ProtectedRoutes, type ModuleRegisterFunction, type FireflyRuntime } from "@squide/firefly";
import { RootLayout } from "./Rootlayout.tsx";
import { AuthenticationBoundary } from "./AuthenticationBoundary.tsx";
Expand Down
10 changes: 6 additions & 4 deletions docs/guides/develop-a-module-in-isolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ host
## Create a shell package

!!!info
The implementation details of the `RootLayout` and `RootErrorBoundary` components won't be covered by this guide as it already has been covered many times by other guides.
The implementation details of the `RootLayout`, `RootErrorBoundary` and `ModuleErrorBoundary` components won't be covered by this guide as it already has been covered many times by other guides.
!!!

First, create a new package (we'll refer to ours as `shell`) and add the following fields to the `package.json` file:
Expand All @@ -54,6 +54,7 @@ Then, create an `AppRouter` component in the shell package to provide a **reusab
```tsx shell/src/AppRouter.tsx
import { AppRouter as FireflyAppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { RootErrorBoundary } from "./RootErrorBoundary.tsx";

export function FireflyAppRouter() {
return (
Expand All @@ -64,6 +65,7 @@ export function FireflyAppRouter() {
router={createBrowserRouter([
{
element: rootRoute,
errorElement: <RootErrorBoundary />
children: registeredRoutes
}
])}
Expand All @@ -81,14 +83,14 @@ Finally, create a local module to register the **application shell**. This modul
```tsx shell/src/register.tsx
import { PublicRoutes, ProtectedRoutes, type ModuleRegisterFunction, type FireflyRuntime } from "@squide/firefly";
import { RootLayout } from "./RootLayout.tsx";
import { RootErrorBoundary } from "./RootErrorBoundary.tsx";
import { ModuleErrorBoundary } from "./ModuleErrorBoundary.tsx";

export const registerShell: ModuleRegisterFunction<FireflyRuntime> = runtime => {
runtime.registerRoute({
element: <RootLayout />,
children: [
{
errorElement: <RootErrorBoundary />,
errorElement: <ModuleErrorBoundary />,
children: [
PublicRoutes,
ProtectedRoutes
Expand All @@ -102,7 +104,7 @@ export const registerShell: ModuleRegisterFunction<FireflyRuntime> = runtime =>
```

!!!info
This guide only covers the `RootLayout` and `RootErrorBoundary` components but the same goes for other shell assets such as an `AuthenticationBoundary` component.
This guide only covers the `RootLayout`, `RootErrorBoundary` and `ModuleErrorBoundary` components but the same goes for other shell assets such as an `AuthenticationBoundary` component.
!!!

## Update the host application
Expand Down
18 changes: 9 additions & 9 deletions docs/guides/isolate-module-failures.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Nevertheless, an application, federated or non-federated, can get very close to

## Create an error boundary

First, define a React Router's error boundary to catch module errors. For this example we'll name it `RootErrorBoundary`:
First, define a React Router's error boundary to catch module errors. For this example we'll name it `ModuleErrorBoundary`:

```tsx host/src/RootErrorBoundary.tsx
export function RootErrorBoundary() {
```tsx host/src/ModuleErrorBoundary.tsx
export function ModuleErrorBoundary() {
return (
<div>An error occured while rendering a page from a module!</div>
)
Expand All @@ -24,22 +24,22 @@ export function RootErrorBoundary() {

## Register the error boundary

Then, update the host application `registerHost` function to declare the `RootErrorBoundary` component below the `RootLayout` component but above the routes of the modules. By doing so, if a module encounters an unhandled error, the error boundary will only replace the section rendered by the `Outlet` component within the root layout rather than the entire page.
Then, update the host application `registerHost` function to declare the `ModuleErrorBoundary` component below the `RootLayout` component but above the routes of the modules. By doing so, if a module encounters an unhandled error, the error boundary will only replace the section rendered by the `Outlet` component within the root layout rather than the entire page.

A React Router's error boundary is declared with the [errorElement](https://reactrouter.com/en/main/route/error-element) of a route:

```tsx !#7,11 host/src/register.tsx
import { PublicRoutes, ProtectedRoutes, type ModuleRegisterFunction, type FireflyRuntime } from "@squide/firefly";
import { RootLayout } from "./RootLayout.tsx";
import { RootErrorBoundary } from "./RootErrorBoundary.tsx";
import { ModuleErrorBoundary } from "./ModuleErrorBoundary.tsx";

export const registerHost: ModuleRegisterFunction<FireflyRuntime> = runtime => {
runtime.registerRoute({
element: <RootLayout />,
children: [
{
// Default error boundary.
errorElement: <RootErrorBoundary />,
// Error boundary for modules.
errorElement: <ModuleErrorBoundary />,
children: [
PublicRoutes,
ProtectedRoutes
Expand All @@ -56,7 +56,7 @@ By implementing this mechanism, the level of failure isolation achieved is **com

### Hoisted pages

If your application is [hoisting pages](../reference/runtime/runtime-class.md#register-an-hoisted-route), it's important to note that they will be rendered outside of the host application's `RootErrorBoundary` component. To prevent breaking the entire application when an hoisted page encounters unhandled errors, it is highly recommended to declare a React Router's error boundary for each hoisted page as well, again using [errorElement](https://reactrouter.com/en/main/route/error-element):
If your application is [hoisting pages](../reference/runtime/runtime-class.md#register-an-hoisted-route), it's important to note that they will be rendered outside of the host application's `ModuleErrorBoundary` component. To prevent breaking the entire application when an hoisted page encounters unhandled errors, it is highly recommended to declare a React Router's error boundary for each hoisted page as well, again using [errorElement](https://reactrouter.com/en/main/route/error-element):

```tsx !#9,11 remote-module/src/register.tsx
import { type ModuleRegisterFunction, type FireflyRuntime } from "@squide/firefly";
Expand All @@ -76,7 +76,7 @@ export const register: ModuleRegisterFunction<FireflyRuntime> = runtime => {

## Try it :rocket:

Start the application in a development environment using the `dev` script. Update any of your application routes that is rendered under the newly created error boundary (e.g. that is not hoisted) and throw an `Error`. The error should be handled by the `RootErrorBoundary` component instead of breaking the whole application.
Start the application in a development environment using the `dev` script. Update any of your application routes that is rendered under the newly created error boundary (e.g. that is not hoisted) and throw an `Error`. The error should be handled by the `ModuleErrorBoundary` component instead of breaking the whole application.

### Troubleshoot issues

Expand Down
24 changes: 10 additions & 14 deletions docs/guides/migrate-to-firefly-v9.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,11 @@ export function App() {
router={createBrowserRouter([
{
element: rootRoute,
errorElement: <RootErrorBoundary />,
children: [
{
errorElement: <RootErrorBoundary />,
children: [
{
element: <BootstrappingRoute />,
children: registeredRoutes
}
]
element: <BootstrappingRoute />,
children: registeredRoutes
}
]
}
Expand Down Expand Up @@ -342,7 +338,7 @@ export const registerHost: ModuleRegisterFunction<FireflyRuntime> = runtime => {

Now:

```tsx !#12
```tsx !#10
export function App() {
return (
<AppRouter waitForMsw>
Expand All @@ -352,12 +348,8 @@ export function App() {
router={createBrowserRouter([
{
element: rootRoute,
children: [
{
errorElement: <RootErrorBoundary />,
children: registeredRoutes
}
]
errorElement: <RootErrorBoundary />,
children: registeredRoutes
}
])}
{...routerProviderProps}
Expand All @@ -375,3 +367,7 @@ The changes in `v9` have minimal impact on module code. To migrate an existing m

1. Convert all deferred routes into static routes. [View example](#removed-support-for-deferred-routes)
2. Add a `$key` option to the navigation item registrations. [View example](#new-key-option-for-navigation-items)

### Isolated development

If your module is set up for [isolated development](../guides/develop-a-module-in-isolation.md), ensure that you also apply the [host application migration steps](#migrate-an-host-application) to your isolated setup.
10 changes: 3 additions & 7 deletions docs/reference/routing/appRouter.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export function RootErrorBoundary() {
}
```

```tsx !#16 host/src/App.tsx
```tsx !#14 host/src/App.tsx
import { AppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { RootErrorBoundary } from "./RootErrorBoundary.tsx";
Expand All @@ -134,12 +134,8 @@ export function App() {
router={createBrowserRouter([
{
element: rootRoute,
children: [
{
errorElement: <RootErrorBoundary />,
children: registeredRoutes
}
]
errorElement: <RootErrorBoundary />,
children: registeredRoutes
}
])}
{...routerProviderProps}
Expand Down
11 changes: 2 additions & 9 deletions docs/reference/routing/protectedRoutes.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,15 @@ None

The route defining the `ProtectedRoutes` placeholder must be [hoisted](../runtime/runtime-class.md#register-an-hoisted-route); otherwise, there will be an infinite loop as the `ProtectedRoutes` placeholder will render within itself.

```tsx !#13,18 shell/src/register.tsx
```tsx !#8,11 shell/src/register.tsx
import { ProtectedRoutes } from "@squide/firefly";
import { RootLayout } from "./RootLayout.tsx";
import { RootErrorBoundary } from "./RootErrorBoundary.tsx";

runtime.registerRoute({
// Pathless route to declare a root layout.
element: <RootLayout />,
children: [
{
// Pathless route to declare a root error boundary.
errorElement: <RootErrorBoundary />,
children: [
ProtectedRoutes
]
}
ProtectedRoutes
]
}, {
hoist: true
Expand Down
11 changes: 2 additions & 9 deletions docs/reference/routing/publicRoutes.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,15 @@ None

The route defining the `PublicRoutes` placeholder must be [hoisted](../runtime/runtime-class.md#register-an-hoisted-route); otherwise, there will be an infinite loop as the `PublicRoutes` placeholder will render within itself.

```tsx !#13,18 shell/src/register.tsx
```tsx !#8,11 shell/src/register.tsx
import { PublicRoutes } from "@squide/firefly";
import { RootLayout } from "./RootLayout.tsx";
import { RootErrorBoundary } from "./RootErrorBoundary.tsx";

runtime.registerRoute({
// Pathless route to declare a root layout.
element: <RootLayout />,
children: [
{
// Pathless route to declare a root error boundary.
errorElement: <RootErrorBoundary />,
children: [
PublicRoutes
]
}
PublicRoutes
]
}, {
hoist: true
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/tanstack-query/useProtectedDataQueries.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export function RootErrorBoundary() {
}
```

```tsx !#58 host/src/App.tsx
```tsx !#55 host/src/App.tsx
import { useProtectedDataQueries, useIsBootstrapping, AppRouter } from "@squide/firefly";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { ApiError, SessionContext, type Session } from "@sample/shared";
Expand Down Expand Up @@ -243,10 +243,10 @@ export function App() {
router={createBrowserRouter([
{
element: rootRoute,
errorElement: <RootErrorBoundary />,
children: [
{
element: <BootstrappingRoute />,
errorElement: <RootErrorBoundary />
children: registeredRoutes
}
]
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/tanstack-query/usePublicDataQueries.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export function RootErrorBoundary() {
}
```

```tsx !#48 host/src/App.tsx
```tsx !#45 host/src/App.tsx
import { usePublicDataQueries, useIsBootstrapping, AppRouter } from "@squide/firefly";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { ApiError, FeatureFlagsContext, type FeatureFlags } from "@sample/shared";
Expand Down Expand Up @@ -204,10 +204,10 @@ export function App() {
router={createBrowserRouter([
{
element: rootRoute,
errorElement: <RootErrorBoundary />,
children: [
{
element: <BootstrappingRoute />,
errorElement: <RootErrorBoundary />
children: registeredRoutes
}
]
Expand Down
4 changes: 2 additions & 2 deletions packages/firefly/src/useProtectedDataQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export function useProtectedDataQueries<T extends Array<any>>(queries: QueriesOp
data: results.map(x => x.data) as MapUseQueryResultToData<QueriesResults<T>>,
errors,
hasErrors: errors.length > 0,
isReady: results.length === queries.length && results.every(x => x.data)
isReady: !results.some(x => x.isPending)
};
}, [queries.length]);
}, []);

const { data, errors: queriesErrors, hasErrors, isReady } = useQueries({
queries: queries.map(x => ({
Expand Down
8 changes: 6 additions & 2 deletions samples/basic/shell/src/AppRouter.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SessionManagerContext, useToastListener } from "@basic/shared";
import { AppRouter as FireflyAppRouter, useIsBootstrapping } from "@squide/firefly";
import { AppRouter as FireflyAppRouter, useIsBootstrapping, useLogger } from "@squide/firefly";
import { useCallback } from "react";
import { Outlet, RouterProvider, createBrowserRouter } from "react-router-dom";
import { Loading } from "./Loading.tsx";
Expand Down Expand Up @@ -32,18 +32,22 @@ function BootstrappingRoute() {
}

export function AppRouter() {
const logger = useLogger();

return (
<FireflyAppRouter waitForMsw={false}>
{({ rootRoute, registeredRoutes, routerProviderProps }) => {
logger.debug("[shell] React Router will be rendered with the following route definitions: ", registeredRoutes);

return (
<RouterProvider
router={createBrowserRouter([
{
element: rootRoute,
errorElement: <RootErrorBoundary />,
children: [
{
element: <BootstrappingRoute />,
errorElement: <RootErrorBoundary />,
children: registeredRoutes
}
]
Expand Down
6 changes: 5 additions & 1 deletion samples/endpoints/shell/src/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export interface AppRouterProps {
}

export function AppRouter(props: AppRouterProps) {
const logger = useLogger();

const {
waitForMsw,
telemetryService
Expand All @@ -114,15 +116,17 @@ export function AppRouter(props: AppRouterProps) {
return (
<FireflyAppRouter waitForMsw={waitForMsw} waitForPublicData waitForProtectedData>
{({ rootRoute, registeredRoutes, routerProviderProps }) => {
logger.debug("[shell] React Router will be rendered with the following route definitions: ", registeredRoutes);

return (
<RouterProvider
router={createBrowserRouter([
{
element: rootRoute,
errorElement: <RootErrorBoundary />,
children: [
{
element: <BootstrappingRoute telemetryService={telemetryService} />,
errorElement: <RootErrorBoundary />,
children: registeredRoutes
}
]
Expand Down
5 changes: 5 additions & 0 deletions templates/getting-started/apps/host/src/NotFoundPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function NotFoundPage() {
return (
<div>Not found! Please try another page.</div>
);
}
6 changes: 6 additions & 0 deletions templates/getting-started/apps/host/src/register.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ProtectedRoutes, PublicRoutes, type FireflyRuntime, type ModuleRegisterFunction } from "@squide/firefly";
import { HomePage } from "./HomePage.tsx";
import { NotFoundPage } from "./NotFoundPage.tsx";
import { RootLayout } from "./RootLayout.tsx";

export const registerHost: ModuleRegisterFunction<FireflyRuntime> = runtime => {
Expand All @@ -16,6 +17,11 @@ export const registerHost: ModuleRegisterFunction<FireflyRuntime> = runtime => {
hoist: true
});

runtime.registerPublicRoute({
path: "*",
element: <NotFoundPage />
});

runtime.registerRoute({
index: true,
element: <HomePage />
Expand Down

0 comments on commit 0c43a84

Please sign in to comment.