React Router v4 FAQ
github.com
github.com
Any time I have to touch react-router I just resign the idea that I'm going to have to take at minimum a day to work out the bugs that pop up with every upgrade, (even minor changes).
> Why the huge change? (AGAIN?!)
> tl;dr Declarative Composability
The huge change is because the maintainers are apparently unwilling or incapable of either A. Creating something good enough on the first, second, or third attempt, or B. are completely oblivious to the needs of devs trying to create practical software and don't understand that project stability is just as important as a good API.
Thanks but no thanks.
I got burned by this in my last big project, we resigned ourselves to never upgrading past 1.0.0-beta4.
Investing in react-router is like investing in a clown. It's a total toss-up. The maintainers could all move on to whatever other hip lib and finally it will be stable, or you can continue betting large sums of money on what is basically a coin flip every 6 months: Are they going to screw with the library again (yes) and will it cause a bunch of bugs in my program (probably). It's a bad investment, esp if you try to upgrade. The ironic part of this is that honestly I feel like the V1 API is the best out of all of them. If they had just iterated and brought breaking changes that were actually needed instead of just those that they felt might be fun, the project would be much better for it in my opinion.
(I know python <-> react-router comparison is apples to oranges but bear with me)
Solving each of these problem introduced some awkward APIs, but the community demanded them with a passion just like in this thread. We all built and learned.
This rewrite is motivated by: (a) knowing the spectrum of use cases, (b) throwing out non-composable APIs that made it hard for everyone to extend the router, (c) eliminating a class of bugs caused by router trying to "orchestrate" everything instead of letting React do it.
It was not obvious to the authors how to do it from day one. It was not obvious to me or anyone else. Everything is easy in hindsight ;-) It's sure rewarding to solve these problems for the authors, but this has nothing to do with "fun" and everything with creating something future users won't hate.
All the churn in previous versions was caused by router fighting with React. Now it works together with React. Let's see how it pans out. And if you're pessimistic, keep using RR3, it's going to be maintained for a long time (you're not the only one using it ;-).
The javascript ecosystem in general is extremely fragile.
I have lost weeks and weeks worth of time investigating how X and Y silently broke again.
And I say that as a hardcore webdev who is very well familiar with Javascript.
Sometimes just makes me want to kiss it goodbye and go back to server or backend development for some sanity and stability.
How does code just magically break on it's own? Either you did something wrong, or you're keeping details back. Code doesn't just work today and not tomorrow on it's own.
Stop blaming others for your mistakes.
npm follows semver and expects libraries to do the same, whether they do or not is up to the library author, but npm can't know if the library does or not. Therefor the user didn't pay attention to the library they are using and blindly installed it and set constraints that caused breaking changes to get into their code. Once again, not the ecosystems fault, but the developers fault.
I said "fragile". That doesn't mean something wasn't objectively "my fault".
Yes the bytes don't change themselves, I was the one making some changes here and there so in that sense it's my fault. But that's a very mechanical and shallow way to think about it.
Javascript as a language and ecosystem makes it extremely easy to create mistakes. In that sense a mistake that I make is partially Javascript's fault too.
Some people look at what I said and think "programming languages need to be better" and some think "humans need to be better".
The people in the second group don't help moving things forward. They just blame people for not being "smart enough" until the people in the first group set a new standard for what things should look like.
Maintaining react-router and keeping up to date for a production site is a full time job I don't want.
I realize I sound like the a whining open source leech but there is a huge opportunity for a stable library to emerge and capture mindshare here.
Where is Facebook during all this? Someone needs to step up and solidify this critical react ecosystem component and it seems like it should be them. Obviously.
It definitely suffers from a documentation problem (the new examples are genuinely great, but previous versions were very light on practical examples and best practices).
Personally, I think that routing in general is one of the major causes of "Javascript Fatigue", and is proof that building complex software is inherently complex.
I will say that despite its "de-facto standard" nature, there's certainly a number of other options out there. I keep a list of Redux-related addons and utilities, and there's a couple dozen entries in the "Routing" category (https://github.com/markerikson/redux-ecosystem-links/blob/ma...). Again, I haven't used any of them myself, but they exist. And that's _just_ "libs that relate to routing and Redux", much less "libs that relate to routing and React, or routing in general".
4.0 represents what we think is a great building block for routing in React applications. But it is not a hard requirement to use it. We think people are going to be more jazzed for 4.0, but there is so much stuff built around 2.x/3.0 that it would be moronic for us to force you into this new structure.
Please, keep your deps at "react-router": "< 4.0.0" if you want to. You won't be penalized for doing so, I promise you.
https://www.google.com/search?q=site:https%3A%2F%2Fwhat.thed...
How about this: if it ain't broke, don't upgrade.
Why? Well, some of it's solid code. That might be worth keeping. But some of it's technologies that fell out of fashion. And there's a bunch of stuff that people wrote in a frenzy, so there's a bunch of tech debt. And even if they stripped it down to the bones, there's a lot of upgrading to do just to get back to where they could do new work with modern libraries. From the business perspective it was easier just to glue together a bunch of outsourced services.
I'm sure those developers all meant well by picking cutting-edge tech. But as Dan McKinley says, we should generally choose boring technology [1]. As you describe, the costs of keeping up with interesting things is substantial. On rare occasions, it's really worth paying that cost. But, mostly, as with my acquaintance's company, the costs can accumulate while your attention is elsewhere, pushing code bases into a sort of technical bankruptcy.
I'd be curious even to see it for the technologies you mention. But as others point out, there are plenty of things newer than PHP that have become pretty boring.
Spring Boot (Java) is really simple and boring yet a lot of capabilities underneath
Also, ASP.NET (c#) - similar deal
Django or Flask (Python)
Backbone.js, jQuery, Bootstrap (JS front end)
Express (JS backend)
Sinatra (Ruby)
PHP 6
Maybe Angular or Ember or even basic React+Flux in the front end if you can contain your enthusiasm
For hosting, find a boring PaaS and avoid the container mud wrestling
For pity's sake use PostgreSQL or MySQL, MongoDB burns
What would you suggest out of these for quick prototyping and just side projects?
https://realpython.com/blog/python/kickstarting-flask-on-ubu...
The latter is also when you might appreciate the fact that its markup language is really just embedded Python (PHP style) - you're trusted to not abuse the power, but you define what "abuse" is.
I was pleasantly surprised at how much functionality I got for free once setup. I probably spent as much time on setting up Oracle and xml/config stuff as dev but it was still super fast to get a solid API built.
This is the case with any mature framework. Rails and Angular just happen to be my favorites, but Django, or Spring and Ember can probably work just as well.
I try to avoid having to put up Angular or anything big on the frontend and just scrape by with jQuery. However, when the interactions are supposed to be "rich" and have a lot of animations, drag/dropping, complex forms that validate on the fly, etc etc...things can get really complex. Then you're back to the old dilemma: you are either going to introduce a full-fledged framework, or write one yourself. In those situations, I pick Angular.
- Angular 2 also looks fine, but that defeats the question which asked about "boring", stable frameworks
sounds like hell!
I've watched React Router grow from one-of-a-handful-of-experimental-routers-for-React-on-GitHub to the most well-known third-party library in the React ecosystem (tied with Redux). In that time, Michael and Ryan have learned plenty. They've also taught plenty. Libraries that experiment with their APIs, like React Router and React Motion, help all of us understand how to wield React better. I learned how to use contexts by dissecting React Router v0, when they were still an undocumented feature.
I understand the frustration that upgrading creates. (My first React project was creating an isomorphic server - I was definitely sensitive to changes in the routing API.) Still, I hate seeing a whinefest every time a free library makes a change that an app author disagrees with. You're always welcome to {fork it, build/use something else, help maintain and give feedback on API direction}. Michael and Ryan are enormously friendly and welcoming to external input.
Trying to embarrass the creators or turn them into some sort of open-source pariahs helps nobody.
I look at the scientific community and their inability to share their data with one another out of paranoia, publishing incentives etc... it's not just bad for science, it's bad for their community - their ability to enjoy each other's company on a daily basis.
So you know - I just feel you gotta be kind to open source maintainers. They didn't break anyone's app. They just released new code that you don't have to use.
>We intend to keep supporting the 3.x branch indefinitely (published separately on npm to aid in migration), although there will likely not be any future major versions based on that code. 4.0 is the future, but we won't leave you hanging if you want to stick with 2.x/3.x.
It's not like they are pulling what Bootstrap did and just leaving everyone on the old version out to die. They are going to be supporting the 3.x branch indefinitely.
If you don't want to move, then don't! It's not going to suddenly explode, they will still accept changes for that branch, and bug fixes will still happen.
The only reason I knew that was because I took at look at v4 yesterday when i was bumping up some of my dependencies before our freeze.
With the recent Bootstrap issues still fresh in many's minds, and the already bad reputation that many think the JS ecosystem is "doomed" to continue, it would help to really drive home the point that you aren't just hanging everyone out to dry.
In all fairness, this is a problem that plagues the whole JS ecosystem and not just this lib, but it's no reason not to mention it anyways.
Web apps were a completely different beast as little as three or four years ago. Despite the incredible progress of the last few years we still don't know the best way to go about architecting SPAs, of course things are going to be a little hairy.
Another issue with React-Router is that fundamentally in a web-based system, the router is the core of your framework (middleware, hand-offs to controllers/views, etc. are all built around the abstraction that the router sets up). With React-Router embracign React Components as their API, it means that your entire application must be built to the same abstraction---entirely within the React system, with components nesting other components.
I feel the problem of making a large javascript application client-side is best dealt with by keeping React as the view only, and putting everything else (router, dispatcher, models, etc.) in the form of another abstraction and not defaulting to component based architecture because that's simply what React does.
Also, check out https://medium.com/@mweststrate/how-to-decouple-state-and-ui.... Michael Westrate talks about using your state container to control routing, instead of letting the components do it then syncing current route to state container. He is the author of mobx and uses it in his example, but I imagine it would work for redux scenarios too.
It came at a great time, in that it really crystallised some ideas I had been having about the friction of using React-Router. So I buckled down and wrote my own router component with HistoryJS & Crossroads.
> Libraries that experiment with their APIs, like React Router and React Motion, help all of us understand how to wield React better
If I read this correctly, you believe that it is still in experimental phase? I don't have any problem with people learning and experimenting, but using major release versions a your petri dish is obnoxious for all the thousands of people using react-router even if it is convenient for the core maintainers. There is a difference between an upgrade and an overhaul, with the extent of the changes over V2,3,4 they might as well have just released a completely new routing library or just maintained an experimental branch to figure out what actually works before releasing a series of major breaking changes in quick succession to the greater world. I'm aware that breaking changes are necessary sometimes, but rapid churn is not necessary, esp once you are post 1.0 release. If there were some burning reason to release an upgrade then that would make sense but this release does not even address some of my major pain points with the API.
I also am not complaining about the cost and personally I don't see any validity in the "it's free so I am beyond reproach" mentality that open source people seem to have. What makes you think that I would thank someone for something that was free even if I didn't want it? Or that anyone would for that matter. Thanking people regardless of what they did, just because they did it for free, is one way to erase market signals which govern the direction of open source projects. I would rather just be candid and honest so that maybe people will remember that me and other devs in general are negatively impacted by breaking changes and therefore will consider keeping projects stable.
I also didn't "try to embarrass the creators" and the only person on here to made this personal was you, who decided to name the maintainers by first name.
Instead of doing any of the things that'd require work (like the creators did), you insult them. They must be oblivious or awful at software, right?
> The huge change is because the maintainers are apparently unwilling or incapable of either A. Creating something good enough on the first, second, or third attempt, or B. are completely oblivious to the needs of devs trying to create practical software and don't understand that project stability is just as important as a good API.
Damn. Most of the time people follow their reasoning with, "I am paying for this, so do the stuff I want exactly how I want." But, This is the first time I've seen someone using the free-market to excuse being a dick to someone who's giving their work out to the world for free. The amount of entitlement mentality in this person is so unreal, I'm literally almost exploding in rage here, because I can't believe anyone would treat anyone else like that.
To the maintainers: 99.999% of people out there are not like this person, and we appreciate your work very much. Thanks for putting that work out there. Your effort is also unreal, but a kind version of unreal!
I think there is some responsibility incumbent on the person implementing the library to actually vet the library for good design and pattern implementations, to ensure they are not adopting someones learn as they go projects (if that is an issue they are trying to avoid). This seems to be endemic in the JS space, as an example, I was surprised at how many people jumped on Angular 1.0 give it's serious design flaws that where evident with just a cursory look at the overall architecture of the software.
Then I have build my own router with `popstate` event and I'm quite happy with it. All the navigation history is pushed to redux. It turns out that it works really well for my needs and application.
The one thing we didn't do was layer on top of a flux solution. Seemed more future proof to not tie to anything other than a routing style. If you wanted to do that with our solution it would be as simple as writing an action to do the url change.
No one has yet figured out a clean abstraction that solves this - yes it is hard to imagine that we still have new problems that were not solved in the 1960s by the Greats. This is not a computer science-y problem; it falls into the spectrum of craft and art than science. It'll be beautiful when it is framed correctly and an elegant solution comes out. From the looks of it, the authors of this library (along with the rest of the client-side router ecosystems) are the closest.
The FAQ satisfactorily answers why they are trying this approach - React brought the concept of 'mounting' UI elements, and it applies equally well to routing as well.
I do share the pain of having to keep up with a changing API; and it is especially biting when it feels gratuitous (which I think is not at all the case here), but let's chalk it up to the cost of being in the bleeding edge, working in one of the most well-paid professions in the world.
JavaScript as a language has a lot of churn, and many times unnecessarily, but there is nuance.
In the React ecosystem I have seen that people sometimes want to abstract too much with no real pragmatic advantages. The result is that the abstraction become verbose to use and get in the way for coding things that produce a better user experience. Things that used to be simple to build.
Keep it simple. Make it more complex only when it is necessary.
Slightly off-topic, but I have observed that front-end engineering posts seems to have lower salaries compared to back-end engineering posts for the same level of seniority. My working theory is that there is a higher supply of front-end devs - most of the self-taught devs I've encountered work on the front-end (Flash -> HTML/Javascript, or Designer -> dev).
Google Maps seems to have solved a version of this problem. There is a unique URL for every position and oriention of your view of the world, including street view.
But even then it doesn't log you in as the user who sent you the link. (That would be crazy.) The link will probably also not include any user-specific display preferences. If Google Maps had a "kilometers from you" widget in the corner, you would not expect that value to be reconstructed from the URL.
So really URLs are not keys to the entire state of the app. They represent a "location" which is both abstract and very specific to the application.
Personally I think of the URL as just another input to the state of the application, really not that different from user events, HTTP responses, etc.
Ok...what's holding you up?
I get the frustration, but if you like an older version you learned, just stay with it and maintain it yourself. Or do your own thing completely with another routing solution. Or roll up your sleeves and write your own. Maybe in a year, if the new version still looks like the way to go, put in the effort to switch over. You have a multitude of options.
People act like the authors of the library are intentionally toying with them. And this is for something that presumably no one has paid for!
The sense of entitlement that erupts every time some non-contiguous jump in progress happens is the far worse meme, to me.
Of course this did mean wrapping it for use on the FE, but that was as easy as copying code form Page.js (another old school project).
It's a simple router that hasn't changed much. I've tried to keep it extensible and simple.
Well, it was "good enough" to be the #1 used solution and be adopted by almost everybody in the ecosystem, even if it wasn't "perfectly nailed" the first, second, or even third time. So, there's that.
If there are some better developers out there that can do it better and with less churn, where are they, and where's their project?
>B. are completely oblivious to the needs of devs trying to create practical software and don't understand that project stability is just as important as a good API.
Well, given the rate of churn in the NPM world, they aren't unlike anybody else...
const App = () => (
<BrowserRouter>
<h1>Hello World</h1>
<Match exactly pattern="/" component={Home} />
<Match pattern="/about" component={About} />
<Miss component={NoMatch}/>
</BrowserRouter>
)
Couldn't we take it one step farther and just use a switch statement? It seems like using pure JavaScript would be more idiomatic React. The URL pattern could be parsed in the data layer, and passed down as props. That way the components don't rely on global state, making them easier to test. const App = (screen, args) => {
let content;
switch (screen) {
case 'home':
content = <Home args={args} />
break;
case 'about':
content = <About args={args} />
break;
default:
content = <NoMatch args={args} />
break;
}
return (
<div>
<h1>Hello World</h1>
{content}
</div>
)
}
It's probably just a matter of preference. Recently I started using React-Storybook, so I've become addicted to "dumb" components.It's basically idiomatic JS vs idiomatic React/JSX.
Edit: To the idiomatic point. The first thing that struct me when using React, was that instead of having to use a custom Component for a for loop I could just use someArray.map(). I see this as a similar situation.
While React-Router had a lot of great convenience features I found that it was surprisingly easy to roll my own redux-compatible version that fit my personal needs with a few lines of code and no additional dependencies.
It's exciting that there are people out there experimenting endlessly to figure out the best APIs to build things with. Just because someone comes up with one idea doesn't mean they're wed to supporting it forever. Or for any amount of time: react-router v3 is open source and you can maintain it yourself if you like it or just want to stick with it but want more.
>We intend to keep supporting the 3.x branch indefinitely (published separately on npm to aid in migration), although there will likely not be any future major versions based on that code. 4.0 is the future, but we won't leave you hanging if you want to stick with 2.x/3.x.
When React came out it was billed as just the "V" in client-side MVC. While just about everybody has their own understanding of MVC, my interpretation of the "V" was that it was about things you can see. So React was going to take my data and maintain a UI based on that data without thrashing on the DOM. Cool!
But nobody seemed to do that at first. They put HTTP requests all sorts of stuff inside the React component, and then handled the requesting, processing, and rendering as internal details to the component.
Then the Flux idea came around, which was (I think) to brand one-directional events as "actions" and then smartly cache/reduce an ongoing stream of actions into a single data structure that represents lots of potentially disparate parts of your application. This also made some amount of sense to me.
Surely there would be lots of things that could create actions: incoming DOM events representing a user's intentions, ajax responses that have potentially new facts about the world, websocket events, signals from the camera and microphone, and anything else that might cause a change in the overall state of the page. With the possible exception of DOM events, which the view should quickly translate into meaningful actions anyways, these actions are really not related to the "V" at all.
So what benefit would I get from authoring the logic of URL-change handlers in JSX? Wouldn't it be nicer to write some JavaScript that handles those events and transforms them into actions?
I don't get it either. I thought we were over describing program behavior in XML?
Why is routing being declared in components in the first place? It seems counterintuitive. There are obvious downsides - so what are the upsides? The README gives no clues.
>We intend to keep supporting the 3.x branch indefinitely (published separately on npm to aid in migration), although there will likely not be any future major versions based on that code. 4.0 is the future, but we won't leave you hanging if you want to stick with 2.x/3.x.
[0]https://github.com/ReactTraining/react-router/releases/tag/v...
Ridiculously simple, no dependency on someone else's weird ever-changing ideas about declarative composable component-based route paradigms, no need to write your routes in a markup language, everybody understands it, extensible as hell, trivial to debug—it's a glorious cascade of beautiful advantages.
Try if/else today!
We got there, but there just hasn't been a simple (to reason about) way to do this in javascript. Acknowledging that the current library is fighting (I would call it an anti-pattern) with react is probably a good step. Thanks devs!
Some advice for anyone that hosts docs outside of the git source tree, make the version information clear. For example, the express documentation http://expressjs.com/en/api.html states very clearly "4.x API".
My mind is trying to justify it like this: Render me a component that's going to manage the state involved in transitioning to a new page ... I guess that kind of makes sense -- since a redirect is an inherently stateful process.
1. https://github.com/ReactTraining/react-router/issues/3847
I also like this joke from github readme:
> Versioning and Stability
> We want React Router to be a stable dependency that’s easy to keep current.
^^ This is the one we developed on my team. No view coupling, uses industry standard underlying components (Express Router), and layers on top of existing applications seamlessly (aka, no view tie in points, just anchor tags).
So that middleware actually requires a solution similar to what Nighthawk provides. The point was to keep the routing and the rendering separate, unlike what react router does.
I can't see all the code unless I zoom out on it:
The next build (now.sh versions URLs) will have both working. Sorry about that!
This is improved a little bit in git, where we do a React.Children.only check: https://github.com/ReactTraining/react-router/commit/5a74d46...
Also based on my testing you need to render a single component inside router, so wrap everything in a <div> like the basic example does: https://react-router-website-xvufzcovng.now.sh/basic
My team uses this, we built it in response to most of us not liking the React Router methodology, and already using Express, it seemed like a good route.
Thanks to all the devs that keep moving forward this wonderful ecosustem.
<BrowserRouter>
<Match pattern="/" component={() => <MyComponent someProp="yep" someOtherProp={myOtherGlobalVar}/>}/>
</BrowserRouter>Not that I have a problem with that; all the more power to them. Especially if it helps support development of these libraries.
Their org was originally called rackt (a rough portmanteau of Ryan florence and michael jACKson). When Facebook donated the reactjs namespace to the community, they moved it there alongside a bunch of other popular community projects.
React Router was the project that taught them React. Since starting it, they decided to quit their day jobs and teach React full-time. rackt (the sandbox of two Internet friends) is now ReactTraining (an actual company). As spicyj said, they probably moved it back to help build brand recognition and use their flagship product to add credibility to their new business.
It's fixed in git, Ryan just needs to push a new build.
Edit: I didn't have any big issue with React router and don't dislike it. It just don't work well with clojurescript/rum. I'm now using a cljs lib called 'bidi' for bidirecional routing (data only) and a small logic to change content reactively based on selected route.
Basically it is just the Express router wrapped with logic from Page.js for catching link clicks and what not.
We do universal rendering with a simple middleware and share all our middleware, rendering and route definitions on both the FE and BE.
Try to insert routing only when you need it. When you're ready for a router, react-router is a great choice. Lots of people are already using it with great success, and you'll find a great community of people willing to help you out.
When you need routing, I suggest trying to use HTML5 pushState API. Figure out how to use it in React, and try to add routing to one of your apps.
After that, I think React Router 4 is going to be a great next thing to try. Get a feel for it and use it if you like it and if it solves your problems. I think RR4 is shaping up to be much better than previous versions.
Disclaimer: I work on the React team.