question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`useFormAction` needs a way to distinguish between layout and index routes

See original GitHub issue

If you have an action on a parent layout route with a form on the page it works as expected.

When you add an index route to the parent, your code breaks because Remix tries to post to the index route now. This happens because useFormAction returns a URL that matches both routes. When the form is submitted to that URL Remix takes the leaf route, which used to be the parent route but is now the index route.

URL search param?

Maybe there’s a better solution, but I’m thinking useFormAction can append a url search param when it needs to disambiguate. We can keep using the normal URL in all cases except when a parent has an index route.

// useFormAction in the parent route when it has an index route
`/some/where?_routeId=${parentRouteId}`

// when it doesn't have an index route we can keep it clean
"/some/where"

// and the index route, if it has an action, will also be
"/some/where"

Of course, we could be like our loader URLs here and always use the routeIds from the search params, but it would be nice to have clean URLs most of the time since they sometimes end up in the browser URL with <Form forceRefresh>.

But even then that URL is gross, maybe there’s a different way?

Bubbling?

There’s an idea in #195 to go up the route tree to find an action. I’m leery about this, but I dunno, maybe I could be convinced. I don’t think it solves the problem though, because if both the parent and the index have an action, a form in the parent still doesn’t know where to post.

Do nothing, just warn in the compiler?

Over in #195 I was thinking this:

It’s definitely weird that simply adding an index route breaks a previously working form, but the confusion isn’t in the behavior of Remix–that behavior is simple: actions always post to the leaf route–the confusion comes from Remix not telling you that something is wrong with your code when it could have. We should fix that.

We know at build time which routes have actions so we can fail the build if you have a layout route with an action AND an index route at the same time. Annoying you have to move the code, but nice that your app won’t build until you do. Typically lots of code moves to the index route when you refactor like this anyway, so it’s not that big of a deal.

I don’t think that anymore. If I have an action in a route, and I put a <Form method="post"> in the route component, I expect the action in that route to be called, not the index route in some other file. In my task management demo app I’ve got a form in the parent route and I had to move the action to the index route, and now that index route’s action has to handle the actions for the parent and it’s own form (it’s got one too!). It’s not right.

Start making the trailing slash have meaning again?

😬

The way a lot of web servers disambiguate this exact case is the trailing slash.

"/some/where"   <-- parent
"/some/where/" < -- index

I think a lot of servers are going to be messing w/ these slashes for “clean URLs” and we’d get into all sorts of trouble with them removing our trailing slash, but I dunno … I kinda love it.

I think right now I’d go with adding the search param in the singular case that a layout route has a form and an index, but I also kinda love the trailing slash idea: it works, the URLs are clean, and it’s old-school.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
ryanflorencecommented, Aug 12, 2021

Just realized we could maybe drop the _data param on loaders if we did the trailing slash, too

0reactions
airjp73commented, Dec 3, 2021

Ran into a related issue today. If you’re on an index route, the action you get from useFormAction and useTransition don’t line up.

Example: If you have a route /foo/index.tsx that looks like this

export const action = () => redirect("/foo");

export default function FooIndex() {
  const actionForPage = useFormAction();
  const actionBeingSubmitted = useTransition().submission?.action;

  return (
    <Form method="post">
      <input name="someField" />
      <button type="submit">Submit</button>
    </Form>
  );
}

Then, when you submit the form, actionForPage will be /foo and actionBeingSubmitted will be /foo?index.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Routing - Remix
This is required to differentiate index routes from their parent layout routes. Consider the following structure, where a URL such as /sales/invoices would...
Read more >
Main Concepts v6.6.1 - React Router
Index Route - A child route with no path that renders in the parent's outlet at the parent's URL. Layout Route - A...
Read more >
Attempted import error: 'Route' is not exported from 'react ...
I'm following the guidance to use only react-router-dom and import BrowserRouter and Route from react-router-dom. But I'm getting an error: ./ ...
Read more >
The Difference Between Route Planning and Route Optimization
Here's what you need to know to choose the right tool for your business. ... Route planning software lets you map out the...
Read more >
Understanding routes and route nesting in Remix
Furthermore, Remix also supports indexed file-routing based on folder structure, i.e., files will automatically be routed the same way as ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found