From 57ee3e9c5614f6aa97a920b3a9529980f6c95106 Mon Sep 17 00:00:00 2001 From: Taylor Lodge Date: Fri, 5 Aug 2022 10:27:36 +1200 Subject: [PATCH] feat(routing): meta prop for onload events Any routing event that is triggered from the first load of the page is now tagged with `meta.onloadEvent` This makes it possible to listen to routing actions externally to the machines and perform an action only if the routing event was triggered by page load, not by a post load navigation. This detection is done by assuming that any routing event generated by mounting an xstate-tree root component within 5000ms of the page being created is a pageload routing event --- src/routing/createRoute/createRoute.ts | 5 +++++ src/utils.ts | 10 ++++++++++ src/xstateTree.tsx | 5 ++++- xstate-tree.api.md | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/routing/createRoute/createRoute.ts b/src/routing/createRoute/createRoute.ts index 6fc5b23..a98b4eb 100644 --- a/src/routing/createRoute/createRoute.ts +++ b/src/routing/createRoute/createRoute.ts @@ -180,6 +180,11 @@ export type SharedMeta = { * If true, use history.replace instead history.push */ replace?: boolean; + + /** + * true if the event was triggered by the initial match of the URL on load + */ + onloadEvent?: boolean; }; /** diff --git a/src/utils.ts b/src/utils.ts index 4cc5976..9bd8b03 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -58,3 +58,13 @@ export type StateMachineToInterpreter = T extends StateMachine< > ? Interpreter : never; + +export function isLikelyPageLoad(): boolean { + // without performance API, we can't tell if this is a page load + if (typeof performance === "undefined") { + return false; + } + + // if it's been < 5 seconds since the page was loaded, it's probably a page load + return performance.now() < 5000; +} diff --git a/src/xstateTree.tsx b/src/xstateTree.tsx index fddb2dd..927b208 100644 --- a/src/xstateTree.tsx +++ b/src/xstateTree.tsx @@ -23,12 +23,14 @@ import { Route, RoutingContext, RoutingEvent, + SharedMeta, } from "./routing"; import { useActiveRouteEvents } from "./routing/providers"; import { GetSlotNames, Slot } from "./slots"; import { XstateTreeMachineStateSchema, GlobalEvents } from "./types"; import { useConstant } from "./useConstant"; import { useService } from "./useService"; +import { isLikelyPageLoad } from "./utils"; export const emitter = new TinyEmitter(); @@ -361,7 +363,8 @@ export function buildRootComponent< routing.basePath, getPathName(), getQueryString(), - setActiveRouteEvents + setActiveRouteEvents, + { onloadEvent: isLikelyPageLoad() } as SharedMeta ); // Hack to ensure the initial location doesn't have undefined state diff --git a/xstate-tree.api.md b/xstate-tree.api.md index 0aee25d..c4894f1 100644 --- a/xstate-tree.api.md +++ b/xstate-tree.api.md @@ -295,6 +295,7 @@ export type SharedMeta = { doNotNotifyReactRouter?: boolean; indexEvent?: boolean; replace?: boolean; + onloadEvent?: boolean; }; // @public (undocumented)