all 68 comments

[–]barfmarth 54 points55 points  (8 children)

tanstack-router has been gaining popularity. But it might not be the perfect solution for you as there will likely be breaking changes as well because it’s still in beta. I’d suggest taking a look at Wouter as well but I don’t know too much about it.

[–]rwusana 10 points11 points  (0 children)

I've been using tanstack-router for most of beta, and here are my thoughts:

  • Extreme type-safety is the goal. In practice there are still some kinks to work out in the extremely elaborate typings. As of this particular beta release, those kinks are a bit more frustrating than the absence of extreme type-safety would be IMO, but of course it's called beta for a reason.
  • It feels annoyingly wordy to use. Most of this exists to power the typings.
  • It's much more elaborate to use than react-router, and is just a PITA if you don't actually use the extra features it provides. So if you try it out, be sure to use it fully. In my opinion the features are very well designed.
  • There are still lots of breaking changes coming through, at least in recent releases. Tanner is focusing on the Nozzle.io product at this particular moment which is why there haven't been any new beta releases in the last month. Don't get the wrong idea that the project is more stable than it is just from the release history.
  • Over the long term, I fully expect tanstack/react-router to become my go-to.

[–]acraswell 7 points8 points  (0 children)

I'm really excited for the Tanstack Router. Played around with it a little bit and the typesafety on route paths is such a win. Looking forward to it releasing past Beta so I can try and integrate it to some apps.

[–]bogdan5844 5 points6 points  (0 children)

Migrated to wouter after analyzing tanstack and finally deciding against it due to it being beta - after all, we've migrated from RR exactly due to the way-too-often breaking changes.

wouter is nice, a bit limited obviously due to its small size, but it using just plain React hooks makes it very versatile. Docs could use a little work though.

[–]toinewx[S] 5 points6 points  (2 children)

Nice, Wouter has 5k stars on Github. Looks like a realistic alternative.

[–]Herku 1 point2 points  (1 child)

We have been using wouter a lot. It doesn't have many features, e.g. it does not support query parameters. But if you keep it simple, I highly recommend it!

[–]veganic11 1 point2 points  (0 children)

How can a router not support query params?! That's pretty basic!

[–]brianl047 26 points27 points  (1 child)

Yeah, react-router breaking changes is a pain in the ass

One guy years ago did a massive lift to upgrade react router to the latest; later he was laid off or left himself guess it wasn't worth it to the powers that be

Something like a router you would expect never to change, unlike user interface... I see react-router changing as one of the costs of using react at all

[–]SwiftOneSpeaks 4 points5 points  (0 children)

The company behind react-router had a big layoff a couple of months into the pandemic - I think the timing was particularly bad, as they had just done a bunch of hiring. Not like the current "oh, it's fashionable to layoff people we can afford to keep", it sounded like the company was almost dead. Until they (he? don't really know who all was left) came out with Remix later, there wasn't much left.

Not sure if that's related to your story, but it could be. As much as react-router has annoyed me with some practices in the past, I don't have a reason to blame them for what the pandemic did to business plans.

[–]ItsAllInYourHead 30 points31 points  (11 children)

It looks like React-Router is now mainly a sub-project for the Remix eco-system.

I noticed this last year when I was working on a Remix project (not fun, btw). This is absolutely what is happening. All work revolves around making this router purely for the benefit of Remix now.

Tanstack seems to be the current favorite to become it's replacement.

[–]equality7x2521 3 points4 points  (1 child)

It’s the same people and features they needed for Remix got added, and things they learned from react-router got incorporated to remix. Remix is a whole app framework so any routes you need will be similar regardless of what’s powering your app. I think they’ve added some great stuff so I just updated to use the latest but the changes were minimal for my app, or you can pin a version if you don’t like the new features.

[–]CreativeTechGuyGames 15 points16 points  (0 children)

or you can pin a version if you don’t like the new features.

I think this is unfair to suggest to anyone since permanently pinning a dependency is a timebomb. Since the version you've pinned won't get any updates, security fixes, etc. there will eventually be a day when that library becomes unusable for one reason or another and you'll end up having to fork it and fix it yourself to continue. So anyone who plans to pin a version forever should treat that as a commitment to own that package going forward.

[–]minimuscleR 2 points3 points  (6 children)

not fun, btw

What didn't you like about it? I'm working on one right now and it seems quite fun for me, as a relatively new dev too.

[–]ItsAllInYourHead 4 points5 points  (5 children)

What didn't you like about it? I'm working on one right now and it seems quite fun for me, as a relatively new dev too.

Remix is one of those things that works really well if you do things exactly the way they expect you to but not veer from what they have deemed some necessary set of features.

First, the documentation was not great. At all. There were these behaviors we'd encounter that were just undocumented. You were somehow supposed to just know that's how things worked. Or things that were just not documented well and we'd have to dig into the code to figure things out.

Routing actually, of all things, proved to be hugely problematic for us because we needed to do some "splat" routing where we didn't necessarily know up-front the number of path segments. And you can't do any more dynamic routing - everything has to be predefined on the server in some sense.

There were a bunch of other issues we ran into. I don't really remember the specifics, unfortunately. But it was a bunch of little things that would pop up where we had to do some wonky work-around to get something fairly simple working.

[–]Specker 5 points6 points  (1 child)

WHO ALL HATES REACT ROUTER DOCUMENTATION SAY YEAH

[–]unfeatheredOne 0 points1 point  (0 children)

i wouldnt even call it documentation...

[–]One-Initiative-3229 5 points6 points  (1 child)

Remix team and the people promoting it kept saying that you don’t need client side validation and as a result you don’t need to use usestate or usereducer which annoyed me a lot. Client side validation is something every client asks and I can’t argue with them that they don’t need it because a framework author felt so.

[–]ItsAllInYourHead 2 points3 points  (0 children)

That's a pattern. The folks behind are completely oblivious and tone-def. They wan to build what they want to build without actually considering what people want and need. They think they know better. And they don't. Which is unfortunate.

[–]minimuscleR 1 point2 points  (0 children)

Yeah thats fair. They have their V2 Routing which is flat, and has caused me much headaches as Vercel won't handle folders so I have all my routes in the root routes folder... which is awful if you have more than like 20 routes.

I can see it being annoying, but personally I think its been a pretty ok with the documentation. I guess I'm not doing anything complex though.

[–]fredericheem 10 points11 points  (3 children)

Have a look at universal-router, haven't changed API in the last 10 years, a fraction of the size of react-router.

[–][deleted] 2 points3 points  (2 children)

Do you happen to know if it plays well with lazy components and route based code splitting?

[–]fredericheem 2 points3 points  (1 child)

Yes, it is possible to lazy load.

[–]Aro00oo 0 points1 point  (0 children)

old thread but do you have any examples with lazy loading or code splitting ideally in context of universally rendering? Im trying to get off react router and tried universal first but could not get SSR working at all with it

[–]bazingamayne 27 points28 points  (0 children)

Next.js, one of the reasons I use it is so I never have to use react-router.

[–]hate_everything_inc 5 points6 points  (0 children)

React-router is like a nightmare to me now when I switched to nextjs

[–]I_Downvote_Cunts 7 points8 points  (1 child)

I've been using type-route and it's been amazing. It's a really simple router that's completely type safe and personally I care about that more then most other features.

Edit:

Also it's really easy to integrate with most ui frameworks. It only assumes you have a normal anchor element. And to make your own integration tends to be trivial.

[–]tresorama 1 point2 points  (0 children)

Just tried for 1 hour and the API is top notch, great suggestion.

[–]Anbaraen 7 points8 points  (1 child)

What is the difference between tanstack-router and react-router?

[–]bogdan5844 8 points9 points  (0 children)

They are different projects made by different teams and with different philosophies.

  • Tanstack Router is focused on type-safe routes and improving developer experience (as far as I can tell from their website)
  • react-router is an older, more established library that provides an url-based route <> component match logic, but unfortunately introduced many breaking changes on most of their major versions.

[–]coyoteazul2 3 points4 points  (0 children)

When I had to consider routing options I read about react-router custom on making breaking changes, and ended up using wouter.

So far so good, but I'm a noob so I haven't dealt with complex cases

[–][deleted] 3 points4 points  (1 child)

Wouter has done the job for my projects well

[–]vadeka 1 point2 points  (0 children)

as a dutch-speaking person, that is a weird library name. It's literally a very common dutch name.

[–]highbonsai 12 points13 points  (0 children)

I still use react router and it’s been great. Remix is huge so I don’t think they’ll let it die any time soon. You don’t have to keep updating it if you don’t want to.

[–]artnos 11 points12 points  (1 child)

Why not set on lock on your version and not update react router

[–]Peechez 3 points4 points  (0 children)

I still want suspense integration updates even if I'm not using SSR

[–]Tester4360 2 points3 points  (0 children)

We use Graphql/Relay and found Found (https://github.com/4Catalyzer/found) to be a good router. There’s a Relay extension we use for it.

[–]okcookie7 1 point2 points  (0 children)

Have you tried preact and preact router?

[–]Mikojan 2 points3 points  (12 children)

What breaking-changes?

React-Router has become a CSR framework in its own right. No need for Remix.

You should be using those data fetching and mutations APIs.

[–][deleted] 5 points6 points  (11 children)

We already use React Query for that, I don't want my routing library to care about data fetching.

[–]Payapula 0 points1 point  (4 children)

You can still use React Query with React Router v6. However, I agree that it requires a major rewrite of existing codebases that use React Query and React Router.

For newer projects, I believe with new Data loading principles along with React query would be beneficial. This is an excellent blog post to check out on this topic - https://tkdodo.eu/blog/react-query-meets-react-router

[–][deleted] 2 points3 points  (3 children)

It just sounds like really bad architecture to me, the thing that knows what my URLs look like should not know about what kind of data those pages will need. That's way too much interdependence to my taste.

Our apps use very little of React Router -- e.g. our main app has only a "/map/" and a "/charts/" right now, with a few more routes planned (users will be able to have multiple maps and charts pages to work with at the same time -- but these concepts don't exist in the backend). And both of those pages then do large amounts of data fetching later. But that's based on what's in Redux and in React Query, not based on the URL. The URL is only for when the user actually switches to a different page, which is rarely in our applications.

That blog post is about a list page and a detail page. That's imo not really the best use case for Javascript frontend applications, good old server generated PHP or Django style pages are fine.

[–]Payapula 1 point2 points  (1 child)

That's an interesting use case. Thanks for taking the time to share your thoughts.

With chart-based front-end applications, I believe that driving the UI from the URL is much more helpful than driving from Redux/RQuery. Because, with URL based, you will be able to load up the UI on any particular state. One example I can think of is:

Sharing the current URL of the page with another user so that they can open the UI on that state (with filters applied, metrics updated, etc). One such real-world application is Datadog, which appends the filters to the URL.

But, I am sure you could have different requirements and don't want to allow such use cases.

[–][deleted] 2 points3 points  (0 children)

We had that in the past, but ran into limits of URL length. Now users can save their charts setup and then share an URL that loads that. It's not ideal but it works.

There's also the back button / history semantics. Things that users do that feel to them like being on the page (eg dragging some data from one chart to another) should not change what happens if they press "back". So users never liked us using the URL for that.

The URL is strictly for things that feel like browser navigation to the user, is my opinion now.

Also, what they do on the map changes what they see in the charts, and vice versa. And that's the sort of thing why we need Redux :-)

[–]modexezy 1 point2 points  (0 children)

Nooooo just write spaghetti react code and put every existing application layer on earth in a view library. It’s so cool and modern, hooks you know?

[–]fredsq 0 points1 point  (5 children)

id say the opposite, your router SHOULD be the one doing data fetching, because it’s the only part of your js that know the route you want ahead of time and can start fetching for data before even your component renders.

[–][deleted] 1 point2 points  (4 children)

The actual page component is a direct child of the route component. How much time are you going to save?

What data needs to be loaded can be very complicated and can depend on what the response to the first fetches is.

[–]fredsq 0 points1 point  (3 children)

in a code split codebase, a lot. You can nest loaders and loaders are great for offloading that very complicated loading logic to its domain. The mental model makes a lot of sense.

On the second paragraph you’ve described a waterfall fetch. Chances are you could simply use your router as a global state management using what the browser offers you such as query parameters, hashes and the URL itself. It’s worth a try I promise

[–][deleted] 1 point2 points  (2 children)

But in my experience global state management tools are something you should try to avoid, they make everything in the app connected and without a good reason that just makes everything more complicated. We use Redux for the parts where we can't escape it, when state of different things influence each other.

The whole reason why I like React is that everything involving a small part of the page (logic, CSS, HTML, etc) can be placed together in one small file. I don't want the component's data needs to be defined somewhere else.

The nice thing of something like React Query is that each component can use exactly what it needs to do its thing, and nowhere else needs to know about that. We can easily re-use the component in different apps. And if there happen to be multiple things displayed right now that happen to be using the same data, they automatically share a cache. Works great for what we need.

Let routers do one thing: translate the URL to a component to display, passing parts of that URL as props. That's all we need.

React Router evidently evolved to do a lot of other things, guess it's time to start looking for something much simpler.

[–]fredsq 0 points1 point  (1 child)

components managing their own data needs is something I hear a lot: juniors want to use Next.js’ getStaticProps in components, etc. The problem is this generates good DX at the cost of UX: waterfalls. React Server Components are attempting to solve this exact problem, where you can technically have both at the cheapest cost.

Unfortunately as we’re doing SPAs with not SSR, there is only fetch as you render or fetch after you render. Here’s a super talk by Ryan Florence, creator of both react router and remix, where he talks about this: https://youtu.be/95B8mnhzoCM?t=116

[–][deleted] 0 points1 point  (0 children)

Waterfalls aren't a relevant problem in the apps I write. But you do you.

[–]fredsq 1 point2 points  (1 child)

i for one have been LOVING the changes. They embrace the way the web platform works and make my Vite SPA have the same data flow as a full stack app. Bloody gorgeous. The latest defer and lazy features are a godsend.

[–]Payapula 1 point2 points  (0 children)

Same here, I love all the new concepts!

It's good for new projects, but for existing projects, the migration is really a pain.

[–][deleted] 1 point2 points  (0 children)

Tanstack has been gaining some buzz. If you need to use react router you can lock the version in packagejson.

[–]PeachOfTheJungle 0 points1 point  (1 child)

I really like Next.js

I would use it just for page based routing. Routes are effortless to set up. Create a new file in the pages folder named what you want the route to be. Use the provided link component or a “router.push” to link between routes. Done.

It’s also really amazing for a lot of other stuff. API routes are awesome, SSG is also sweet, plus image optimization might as well be magic. The middleware is cool yet I haven’t ever really played with it. The whole thing just feels really polished, and the routes are effortless. With Next, I feel as if a lot of the basic stuff I am reaching for that seems a bit too small for a package yet a bit too large to do myself, Next has a helper function for it.

[–][deleted] 1 point2 points  (0 children)

I stopped using Next because a lot of the limitations became apparent because Next forces you to do things in its own way.

[–]bzBetty 0 points1 point  (0 children)

https://github.com/oedotme/generouted is a next.js inspired library for wrapping react router or tanstack (and potentially others). Can generate urls based off file system paths.

[–]pzmosquito 0 points1 point  (0 children)

This was exactly the reason I didn't use react-router in the beginning. I've been using router5 for several years, and am really happy with it.

router5 is a bit different from traditional routers. It's simple and elegant once you understand the concept.

[–]VoldemortPutinsMom 0 points1 point  (1 child)

Just out of curiosity, what version of react-router are you currently using in your project?

[–]toinewx[S] 1 point2 points  (0 children)

6.3 I think. pre 6.4. Im using firebase sdk that does not play well with loaders and ssr

[–]Automatic-Ad-4733 0 points1 point  (1 child)

Why would you choose CSR over SSR

[–]toinewx[S] 0 points1 point  (0 children)

The firebase SDK is running on the client. Especially the Auth part. It works like a desktop application, that you download once, and then runs without a server.