SolidJSS
SolidJSโ€ข10mo ago
danchez

How to Abstract Routers using Classes

I'm trying to create a library that leverages a subset of routing functions under the hood. With the release of TanStack Router for SolidJS, I do not want to couple the library specifically to Solid Router and want to provide a Router abstraction that consumers of the library can configure with their router of choice. The way I'm going about that is providing abstract Router classes. Below is one example:

import { type Accessor, createSignal } from "solid-js";

import type { Router } from "./types";

export class SolidRouter implements Router {
  private router: typeof import("@solidjs/router") | undefined;
  public loaded: Accessor<boolean>;

  constructor() {
    const [loaded, setLoaded] = createSignal(false);

    this.loaded = loaded;

    import("@solidjs/router").then((routerModule) => {
      this.router = routerModule;
      setLoaded(true);
    });
  }

  pathname = () => {
    if (!this.router || !this.loaded()) {
      throw new Error("Router not loaded");
    }

    return this.router.useLocation().pathname;
  };

  getSearchParam = (key: string) => {
    if (!this.router || !this.loaded()) {
      throw new Error("Router not loaded");
    }

    const [searchParams] = this.router.useSearchParams();
    return searchParams[key] as string | null;
  };

  navigate = (path: string, options?: { replace?: boolean }) => {
    if (!this.router || !this.loaded()) {
      throw new Error("Router not loaded");
    }

    const _navigate = this.router.useNavigate();
    _navigate(path, options);
  };
}


The same pattern above is applied for TanStackRouter as I dynamically load the library in the constructor and implement the same interfaces with all the things that TanStack Router expects. I have two primary questions:

1. Is the above paradigm a good way of going about providing the abstraction over routing? If not, what's another way that allows users to configure routing.
2. Every time I use the class, I am getting an exception at the point of the navigate interface being called despite it being invoked while being a descendant of a <Router /> component in the JSX tree:

Uncaught (in promise) Error: <A> and 'use' router primitives can be only used inside a Route.
    at invariant (utils.js?v=23f17e0f:29:15)
    at useRouter (routing.js?v=23f17e0f:9:32)
    at Module.useNavigate (routing.js?v=23f17e0f:42:34)
    at SolidRouter.navigate (SolidRouter.tsx:42:35)
    at runCallback (useLib.ts:120:14)


Not sure how to debug the error. I suppose it has something to do with invoking const _navigate = this.router.useNavigate(); in the context of a class and not a component? ๐Ÿค”
Was this page helpful?