router icon indicating copy to clipboard operation
router copied to clipboard

Cannot update path params when navigating to `'.'`

Open levrik opened this issue 1 year ago • 2 comments

Which project does this relate to?

Router

Describe the bug

I wrote a hook which should replace the slug in the URL if it doesn't match reality anymore. For example /projects/here-is-the-name-123 -> /projects/new-name-123.

navigate({ to: '.', params: { slug: 'new-name' }, replace: true });

Replacing search works without issues this way but not with params.

Your Example Website or App

https://stackblitz.com/edit/github-aitiwm?file=src%2Fmain.tsx

Steps to Reproduce the Bug or Issue

  1. Click on "Project 123" or "Document 123" link
  2. See old slug from path params rendered
  3. It should replace after 1 second but it does not

You can try replacing the to: '.' by a real route and see how it works but this then does not work for 2 different routes anymore.

Expected behavior

Path params to get replaced when navigating to '.'.

Screenshots or Videos

No response

Platform

  • OS: macOS
  • Browser: Edge
  • Version: 129

Additional context

No response

levrik avatar Sep 26 '24 07:09 levrik

@levrik not sure what your end goal is but you can achieve the same functionality if you just pass the path in useFixUrl and use that path in the to: "path" option. Am not sure why . is not able to pick up the current route.

Code:

import React, { StrictMode, useEffect } from 'react';
import ReactDOM from 'react-dom/client';
import {
  Link,
  Outlet,
  RouterProvider,
  createRootRoute,
  createRoute,
  createRouter,
  useNavigate,
  useParams,
} from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/router-devtools';

const rootRoute = createRootRoute({
  component: () => (
    <>
      <div className="p-2 flex gap-2">
        <Link to="/" className="[&.active]:font-bold">
          Home
        </Link>{' '}
        <Link
          to="/projects/$slug"
          params={{ slug: 'old-name-123' }}
          className="[&.active]:font-bold"
        >
          Project 123
        </Link>{' '}
        <Link
          to="/projects/$slug/$documentId"
          params={{ slug: 'old-name-123', documentId: '123' }}
          className="[&.active]:font-bold"
        >
          Document 123
        </Link>
      </div>
      <hr />
      <Outlet />
      <TanStackRouterDevtools />
    </>
  ),
});

const indexRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/',
  component: function Index() {
    return (
      <div className="p-2">
        <h3>Welcome Home!</h3>
      </div>
    );
  },
});

function useFixUrl(path: string) {
  const navigate = useNavigate();
  const slug = useParams({ strict: false, select: ({ slug }) => slug });

  useEffect(() => {
    if (slug !== 'new-name-123') {
      // Delayed for demonstration purposes
      setTimeout(() => {
        navigate({
          to: path,
          params: { slug: 'new-name-123' },
          replace: true,
        });
      }, 1000);
    }
  });

  return slug;
}

const projectsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/projects/$slug',
  component: function Project() {
    const slug = useFixUrl('/projects/$slug');

    return <div className="p-2">Hello from Projects {slug}!</div>;
  },
});

const documentsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/projects/$slug/$documentId',
  component: function Project() {
    const slug = useFixUrl('/projects/$slug/$documentId');

    return <div className="p-2">Hello from Documents {slug}!</div>;
  },
});

const routeTree = rootRoute.addChildren([
  indexRoute,
  projectsRoute,
  documentsRoute,
]);

const router = createRouter({ routeTree, defaultPreload: 'intent' });

declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router;
  }
}

const rootElement = document.getElementById('app')!;
if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(
    <StrictMode>
      <RouterProvider router={router} />
    </StrictMode>
  );
}

The "." being not able to pick up the current route is something we should definitely take a look at.

Lokendra-sinh avatar Sep 29 '24 11:09 Lokendra-sinh

@Lokendra-sinh Yeah. That would probably work but is also more prone to errors when being copied around for example. Also route components cannot be nested (using Outlet) with it as otherwise calling the hook on parent route and child route would conflict. So getting "." fixed is still required for it to work in all cases.

levrik avatar Sep 30 '24 07:09 levrik

Any updates on this?

Rendez avatar Jan 21 '25 08:01 Rendez

@schiller-manuel As mentioned by @bradymwilliams in #2801 already, this still doesn't fix the issue. This issue is specifically about navigating to . without a from. Please re-open!

levrik avatar Mar 04 '25 07:03 levrik

@levrik see https://github.com/TanStack/router/pull/3654

schiller-manuel avatar Mar 04 '25 09:03 schiller-manuel

@schiller-manuel That was fast. Test case looks like it solves this issue for real. Thanks a lot!

levrik avatar Mar 04 '25 09:03 levrik