Next.js Discord

Discord Forum

Implementing a similar router in JS and was wondering if any improvements could be made?

Unanswered
Olive-sided Flycatcher posted this in #help-forum
Open in Discord
Avatar
Olive-sided FlycatcherOP
Hey guys I was messing around with a single page application and wanted to implement my own router.

I implemented dynamic routes and made it where params could be passed to the routes.

Was wondering if any improvements could be made to this implementation? It's just using console.logs for now.

Router Class:
class Router {
  constructor() {
    this.routes = [
      { path: "/", view: () => console.log("HOME") },
      { path: "/404", view: () => console.log("404 NOT FOUND") },
    ];
  }

  matchRouteSegments(path, routePath) {
    const pathSegments = path.split("/").filter((segment) => segment !== "");
    const routeSegments = routePath
      .split("/")
      .filter((segment) => segment !== "");

    if (pathSegments.length !== routeSegments.length) {
      return null;
    }

    const params = {};

    for (let i = 0; i < routeSegments.length; i++) {
      const routeSegment = routeSegments[i];
      const pathSegment = pathSegments[i];

      if (routeSegment.startsWith("[") && routeSegment.endsWith("]")) {
        const paramName = routeSegment.substring(1, routeSegment.length - 1);
        params[paramName] = pathSegment;
      } else if (routeSegment !== pathSegment) {
        return null;
      }
    }

    return params;
  }

  useParams() {
    const currentPath = location.pathname;
    let params = null;

    this.routes.forEach((route) => {
      const routeParams = this.matchRouteSegments(currentPath, route.path);
      if (routeParams) {
        params = routeParams;
      }
    });

    return params;
  }

  render() {
    const currentPath = location.pathname;
    let match =
      this.routes.find((route) => {
        const params = this.matchRouteSegments(currentPath, route.path);
        if (params) {
          route.params = params;
          return true;
        }
        return false;
      }) ||
      this.routes.find((route) => route.path === currentPath) ||
      this.routes.find((route) => route.path === "/404");

    if (match.params) {
      match.view(match.params);
    } else {
      match.view();
    }
  }

  addRoute(path, view) {
    this.routes.push({ path, view });
  }

  push(route) {
    history.pushState(null, null, route);
    this.render();
  }
}

export { Router };


Here's how I use the Router.
index.js file
import { Router } from "./router.js";

const Posts = (params) => {
  return console.log("POSTS", params);
};

const Post = (params) => console.log("POST WITH ID", params);

const Comment = (params) => {
  return console.log("COMMENT WITH ID", params?.commentId);
};

document.addEventListener("DOMContentLoaded", () => {
  const router = new Router();

  router.addRoute("/posts", Posts);
  router.addRoute("/posts/[postId]", Post);
  router.addRoute("/posts/[postId]/comments/[commentId]", Comment);

  router.render();

  document.body.addEventListener("click", (e) => {
    if (e.target.matches("[data-link]")) {
      e.preventDefault();
      router.push(e.target.href);
    }
  });
});


Html just has an 'a' tag with data-link and href="posts" I manually typed in the /posts/1 and /posts/1/comments/1 lol


Server is this:
server.js
const express = require("express");
const path = require("path");
const app = express();
const port = 3000;

app.use(
  "/static",
  express.static(path.resolve(__dirname, "frontend", "static"))
);

app.get("/*", (req, res) => {
  res.sendFile(path.resolve(__dirname, "frontend", "index.html"));
});

app.listen(process.env.PORT || port, () => console.log("SERVER IS RUNNING..."));

0 Replies