Skip to content

Tutorial — your first session

Install, start a session, subscribe to events, read snapshot state, dispose.

Previous: Core concepts · Next: Visibility

Playground

Visibility explorer — switch tabs and observe event order.

Prerequisites: Node 20+, browser or SSR-aware bootstrap.


Step 1 — Install

bash
npm install @jayoncode/browser-lifecycle

Outcome: Package available for import.


Step 2 — Create a session

ts
import { createBrowserLifecycle } from "@jayoncode/browser-lifecycle";

const lifecycle = createBrowserLifecycle({ autoStart: true });

Outcome: Session in running phase with modules attached per configuration.


Step 3 — Subscribe to events

ts
lifecycle.on("page:visible", () => {
  resumePolling();
});

lifecycle.on("page:hidden", () => {
  pausePolling();
});

Outcome: Handlers run on normalized visibility transitions. Unsubscribe via returned function.


Step 4 — Read snapshot

ts
const snapshot = lifecycle.getSnapshot();
console.log(snapshot.page.visibility); // "visible" | "hidden"

Outcome: Readonly view of current session state without manual listener bookkeeping.


UI structure (framework shell)

Browser Lifecycle has no form markup — mount one shared session and dispose on unmount.

React JSX

tsx
import { useEffect, useMemo } from "react";
import { createBrowserLifecycle } from "@jayoncode/browser-lifecycle";

export function AppShell({ children }: { children: React.ReactNode }) {
  const lifecycle = useMemo(() => createBrowserLifecycle({ autoStart: true }), []);

  useEffect(() => {
    const offVisible = lifecycle.on("page:visible", () => resumeWork());
    const offHidden = lifecycle.on("page:hidden", () => pauseWork());

    return () => {
      offVisible();
      offHidden();
      void lifecycle.dispose();
    };
  }, [lifecycle]);

  return <>{children}</>;
}

Vanilla HTML + module script

html
<body>
  <main id="app"><!-- your UI --></main>
  <script type="module">
    import { createBrowserLifecycle } from "@jayoncode/browser-lifecycle";

    const lifecycle = createBrowserLifecycle({ autoStart: true });
    lifecycle.on("page:hidden", () => console.log("tab hidden"));

    window.addEventListener("pagehide", () => {
      void lifecycle.dispose();
    });
  </script>
</body>

Step 5 — Dispose

ts
await lifecycle.dispose();

Outcome: Listeners removed; instance must not be reused.


Recap

StepAPIResult
1npm installDependency installed
2createBrowserLifecycle()Active session
3on(event, handler)Typed subscriptions
4getSnapshot()Current state
5dispose()Clean teardown

Pitfalls

IssueMitigation
Multiple sessions per tabSingle shared instance
Missing teardownCall dispose() on unmount
SSR accessGuard typeof window !== "undefined"

Continue

TopicGuidePlayground
Visibility moduleVisibilityVisibility
Event patternsEventsEvents
Config & SSRCore infrastructureConfiguration

Quick start · FAQ

JOC is a JayOnCode monorepo of @jayoncode/* packages. Docs sync from source via TypeDoc and sync scripts.