React Router works well enough but I've had a lot of problems using it. One issue in particular I've had with this project is that they change the API so frequently that it's often difficult or nigh impossible to find documentation on issues, how to do X, or access property Y. There are the official docs, but sections have been scant or incomplete, and in some cases wrong. Crucial information might be omitted or only found in another location. Reading other people's projects or old issues is a pain because there is example of using API "X" but now it is named "Y" and does exactly the same thing so you have to go look up the release notes to even find out if the issue is relevant to you.
My project broke the other day because when you provide multiple child components it used to create an object that was "this.props.children.component1" but now it just does "this.props.component1". But when you only pass one component it is still named "this.props.children" in spite of there only being one component. I was unable to find any convincing reasoning for making this change. Does exactly the same thing. Makes the interface less sensible in my opinion. Caused me to do unnecessary work to achieve exactly the same result.
I get that changes are necessary when they change functionality but a lot of times it seems things have just changed with no reasoning other than just changing for the sake of changing. Maybe I'm being unreasonable and overly picky but I wish they would just keep the API stable and make the changes behind the scenes.
Our top priority after we get 2.0 solidly released is to revamp the documentation and provide a better tutorial. The work that Dan Abramov has done with introducing Redux is a positive example to all of us.
As for the change to the case with using multiple named child components - we made that change because React upstream made it no longer valid to pass objects into this.props.children. It wasn't that we decided one way or the other that it was nicer to spread named children into top-level props; the old way that we did it (which for this case was arguably cleaner) was literally no longer supported by React, so we had no choice.
That doesn't sound right. You can pass whatever you want as props to a composite component; you just can't use objects as a list of children in a DOM component, but that's not what you were doing before. When Ryan Florence filed an issue with seemingly your same misconception, we told him the same and never heard back:
This matches my experience with react-router. I use it in a few side projects, and I have the feeling that there's been a lot of "design-thrash" - every new release seems to bring a new interface and new ways of doing things, without much real benefit.
I couldn't agree more. I have used react-router for 3 side projects now, each time with a new interface and no real benefit over the last version, not to mention more outdated docs and advice.
This has been an issue for me with the entire React ecosystem. Trying to get react hot loading working between all the expected latest packages last week was insanely hard.
Hey, I'm on the rackt team and work on both react-router and redux. I joined on around the time of the 1.0 rc's. I can't really speak to the pre-0.13 days, but I've been involved in this most recent rewrite pretty heavily.
A lot of the motivations from 0.13 to 1.0 were around the APIs very liberally mixing React conventions with plain Javascript conventions, with a dash of callback hell thrown in for good measure. In addition, getting access to a lot of the internal APIs for integrations with things like redux and relay was very difficult. So, there was a very large rewrite to better modularize the code and improve the semantics of the API. I think they got pretty close to a good goal, but obviously there was room for improvement.
2.0's motivations have been around further simplifying a lot of the API surface area, particularly in relation to the history sub-project (which is a wrapper around location.hash, HTML5 pushState, and pure memory location state histories). history (which was a peerDep) was a big problem because we tried to stay hands off from that API as much as possible. This ended up putting a lot of mental load on the user, because they now had to be aware of and learn two libraries. So, we're now wrapping things up under a single API provided via `this.context.router` and provided pre-built history objects so you can choose what kind of history (hash or pushstate) you want with much less code and overhead.
Another important thing in this upcoming version is backwards compatibility. We want to avoid the hassles you're having with things breaking all the time. If this version doesn't work with your code built for 1.0, then that's a bug and a blocker for release. We're following React's lead for post-1.0 versioning: https://gist.github.com/zpao/6e12ee0f46ce87af2287#versioning That is, we will release new APIs with each major version and deprecate but support any upcoming API removals. You'll have a chance to test against those removals by looking for dev-only warnings, but everything should work drop-in. As a bonus, we're also shipping a series of jscodeshift codemods to automatically upgrade your existing code to the newer APIs: https://github.com/rackt/rackt-codemod Check those out, because they're really cool and Jimmy Jia worked to make them a part of our upgrade path.
Now, as for your mentioned issue, that was actually a change in a rc version. Yes, changing an API in a release candidate is bad. No way around it: that's our mistake. There was a good reason for this, as it caused bugs with React.Children.map: https://github.com/rackt/react-router/issues/1968 The 1.0 release process was super-rocky and we're looking to avoid that in the future. For 2.0, our API is stable and works to the best of our knowledge. No additions or removals will happen before the final version, so the rc badge is being properly used this time.
We're also making sure our documentation for upgrades and general use are up-to-date and super-clear. The 2.0 API actually came about because Ryan Florence went to go make a screencast series and ran into many of the common problems with the 1.0 API. So, documentation drives our development pretty hard now. We still have a LOT to do, but we are working on it in earnest and my personal goal is to have some of the best documentation out there when all is said and done.
If you have any other suggestions, criticisms, or questions about the APIs, please get in touch on Github via an issue or hop on the Reactiflux chat on Discord. We're all nice, reasonable guys who want to help and make this a great library for both power users and beginners alike. We need more feedback like this so we can make sure we're moving in the right direction. I promise we won't bite!
This ended up putting a lot of mental load on the user, because they now had to be aware of and learn two libraries.
This problem is endemic in the JS world these days. Sure breaking things up into independent modules is a good thing up to a point. But having dozens of little dependencies for every library with their own compatibility issues gets unmanageable very quickly.
You are free to evaluate the stability of any open source projects you would like to use, and if they provide insufficient value, you may get involved, or donate, or use any of the competitors like Backbone.Router or write your own, or otherwise add value to the ecosystem yourself.
Fast paced innovation is good. If you don't like life on the edge, it's not like these problems were unsolved last year. Use those solutions.
after banging my head against react-router for a side-project the past couple of weeks, reading that one of their motivations for 2.0 was to clean up the interaction between history and router was a sigh of relief. looking at the docs, however, made it clear that they are doubling down on their strange and confusing history API:
import { useRouterHistory, hashHistory } from 'react-router'
// useRouterHistory creates a composable higher-order function
const appHistory = useRouterHistory(hashHistory)({ queryKey: false })
<Router history={appHistory}/>
if i wanted to change the scroll behavior of router, then i'd have to do something like this:
how does this make using router/history any clearer?
i LIKE react-router, i think it's pretty damn good, but I just don't understand the rationale for their API choices. combine that with the velocity at which they're changing the APIs, it makes me wish that they'd just take their time with the design
One perk is that you can then navigate using the singleton if you want, e.g. with
browserHistory.push('/foo');
The scroll behavior stuff is definitely messy; I haven't had time to clean it up. The nice thing about OSS, though, is that the rest of you are all free to contribute changes.
I'm personally averse to the whole singleton thing. What about server side rendering? You don't want the history to be shared across requests.
Most projects already have their own ways to pass dependencies (through DI or whatnot), and I can't help but feel like providing those singletons is going to end up messy.
We export createMemoryHistory instead of a singleton for the server. If you don't like the singletons on the browser side, you can use the useRouter enhancer to pop in any history creation function you'd like.
Of course, that API is quite opaque and doesn't give you a history object you work with. It's really just a boilerplate reducer or macro for SSR. You can copy out what's going on inside of the function, but that's pretty crappy for you to have to manage.
I think, in addition to the docs sucking, we need to come up with a better API for SSR. If you're using redux-simple-router or other integrations that rely on history, it's entirely unusable. We need to fix this.
gotcha.
do you have an example for the client side history management with ES6 ? Its been a challenge to figure out the right documentation for ES6 - especially the proptypes declaration.
I dont think you need to do a lot of explanatory docs - if you have canonical examples, that would be more than enough.
I'm working on a universal app right now, and I've found a lot of success factoring aspects like middleware setup and router setup, so that they can differ between client and server sides. On the server side, no actions are ever dispatched, so no router methods ever get called. The only thing I use the Router for is matching the route to know what to pre-fetch before rendering.
React Router has been iterating towards better APIs for advanced use cases (server-side rendering, code splitting, relay (and other lib) integration, etc). Having used it in projects spanning the above use cases, the evolution of the API has been welcome change.
I'm also happy to see codemods and other AST manipulations (such as babel plugins) gaining popularity. Similar to eslint's --fix, codemods are making repetitive changes easier across large codebases.
I'm skeptical of this as well, and while I had no problems with react-router on a side project, I have misgivings with the router being coupled to JSX - IMO, this is an unnecessary coupling of what should be service logic to components.
For the downvoters, this is satire... I'm not the same poster that was 'skeptical' of react router. I have used both libraries and think they're great at what they're intended for.
The problem isn't using React in that situation per se but just that server side templating (React or not) would be a better choice. I assume that's what the commenter meant.
I think it may be time for the community or Facebook to write something that replaces react-router.
It has been extremely difficult to build something on top of it and keep current. Pre-1.0 I can understand the API thrash but 1.0->2.0 in a couple months?
Facebook should carry the torch here and write a standard router. This is a core component critical to the success of React for any applications more complicated than a dashboard.
If anything, working on react-router-relay has only made me appreciate React Router's design more.
A lot of the changes in 2.x are specifically from lessons we've learned in building react-router-relay and other integrations, but they're closer to refactorings and code reorganization than to wholesale rewrites.
Generally what many others have said: that the API has changed a lot.
Specifically I didn't like it when named routes were removed.
But hey—it's open source. Sometimes I get worked up about this or that, but then I remember that all of this I'm getting for free and I must be grateful.
I'm glad to see this thread and some debate about react router and it's features and ways it could be better. Too often any react critisism is attacked almost fanatically.
The community consensus is that deprecation warnings don't strictly require major version bumps.
That said, the React Router 2.x release does also include a few actual breaking changes to APIs that were only used by integrations - which is to say that 2.x is a minor release for end users, but is a major release from the perspective of maintainers of packages like react-router-relay or redux-simple-router.
Got it, thanks. Would it have been easier for you as a dev if they made this a minor version bump rather than a major version? Given that the code and documentation changes would have been the same.
It looks like all the comments by VeilEm are deleted now, which is unfortunate. No matter how controversial or indelicately phrased, you expressed frustrations with an open source project that no doubt also have and I think you should stand by what you said.
Oh, poor you. How dare someone else's work done freely for you not comply to a fairy tale standard like SemVer. This world is so cruel sometimes. Isn't it?
One of the great insights in life is that just because somethings is not followed 100% perfectly it doesn't mean it's useless, or that we'd be better off if we didn't follow it at all.
sure, but in case of something like symanitc versioning, the benefit, at least as far as I understand is to give you some sort of trust or guarantee, _ if you upgrade a package from 1.1 to 1.7 your app will not break_ if in practice 2 out of 10 times the your app did break, then is there really a point? should I trust it?
to be honest I am. if you told NPM to install the latest 1.x and you were on 1.1 and now got upgraded to 1.7 I would put my money on something breaking than not.
The two way binding helpers are just there for people who want to try React without giving up two way binding (eg. people coming from Angular). They are not the recommended way of doing things, and that page says as much.
They're trying to direct newbies away from mistakenly thinking ReactLink is the 'right way'. Seems to only exist so people coming from two way data binding centric frameworks won't immediately discard React out of hand because it 'can't do two way data binding', before they get to know the framework's ideas and realise that two way data binding is usually a bad idea anyway; a notion which is fairly central to React's design. As an experienced React dev, I've never seen ReactLink in real-world use.
See the docs page called Thinking in React [1] and grep through all the mentions of 'data flow' and you'll see how one way (circular) data flow is how React is intended to be used.
React as just a view layer is amazing, but I agree that Flux/Redux + React Router etc. feel like they're reinventing Angular.
The two-way binding is definitely a feature that needs to be used cautiously. I'm not using it in my current project, but it would remove so much boilerplate for us, when it comes to forms. I would only use it for complex controlled forms, never to control application state.
Redux / Flux / React Router have absolutely nothing in common with Angular. It might benefit you to look into each of these things with some attention because they are vastly simpler once understood.
My project broke the other day because when you provide multiple child components it used to create an object that was "this.props.children.component1" but now it just does "this.props.component1". But when you only pass one component it is still named "this.props.children" in spite of there only being one component. I was unable to find any convincing reasoning for making this change. Does exactly the same thing. Makes the interface less sensible in my opinion. Caused me to do unnecessary work to achieve exactly the same result.
I get that changes are necessary when they change functionality but a lot of times it seems things have just changed with no reasoning other than just changing for the sake of changing. Maybe I'm being unreasonable and overly picky but I wish they would just keep the API stable and make the changes behind the scenes.