-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Remove misleading example from upgrade guide #2992
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove misleading example from upgrade guide #2992
Conversation
I'd say that example encourages bad patterns, so it should go completely. Thanks! |
Remove misleading example from upgrade guide
Wait, no, this example is not broken for the same reason. The problem is something like: <button onClick={browserHistory.goBack}> This is fine, net of issues with binding handlers in render: <button onClick={() => browserHistory.goBack()}> |
<button onClick={() => browserHistory.goBack()}> This doesn't break during a render test, but it does when you test the Also, the point wasn't whether this example is broken as-is -- just that it encourages a fragile pattern. The testing example is only a symptom. |
No, but if you're testing the click behavior, presumably you can take whatever steps are necessary to make this work appropriately. It's not my favorite pattern, but the one documented in the example is not as fragile as the one from your issue. |
👍 |
Fine. |
??? There is only one url, there is nothing wrong with singleton histories. They aren't used in server rendering. |
Like, this is one of the major features of 2.0, singleton histories. Are people just freaking out by the word "singleton" or is there a real reason to discourage using them? Why even have them if we're going to discourage using them? |
I'd be happy with bringing this back, especially in light of discussion in reactjs/react-router-redux#257. I'd just say that this pattern can be a bit dangerous on the server, and that in a component you "should" probably prefer |
Yeah, a better example would be using it outside of React entirely. |
You don't use them on the server. |
on the server all redirects are going to happen in route hooks, maybe that's the documentation that needs to happen. |
@ryanflorence Take a look at discussion in #2991. It's not that they're used intentionally by the server, but that since their contracts differ in non-browser envs, they have potential to break the server/tests. |
If you're using something like async-props (or react-resolver), that can be hard. I think this is a fine pattern, but it runs a little bit of risk for being tricky for isomorphic rendering. I don't think this is a good response to #2991, though – the example given in the docs here would not have issues when rendered on the server. |
As you say in #2991
Exactly as designed. There is no such thing as a browser history on the server.
What's wrong with that? |
Beat you to it: #2992 (comment) 😛 On balance, I think this usage is probably fine. I'm not going to use this syntax, but the cases where it causes problems are ones that novice users are unlikely to hit anyway. |
When you are server rendering, novice or pro, you must learn what stuff runs on the server and what runs on the client. There is no such thing as a browser history on the server. It should not be some object w/ a bunch of empty functions to allow naive button click handlers. |
We definitely need to have a doc that talks more about server rendering and gotchas like this. |
What I mean in the server rendering context is that if you call e.g. But this even is a more advanced usage, since normally (but not always) this can be dealt with in the Should we just revert this change for now? |
Suppose you have: const MyButton = props => (
<button onClick={() => {props.doThing(); browserHistory.push('...')}} />
) Testing the callback will throw: import {it} from 'mocha'
import {spy} from 'sinon'
import {shallow} from 'enzyme'
import {assert} from 'chai'
it('fires a callback when clicked', () => {
const callback = spy()
const button = shallow(<MyButton doThing={callback} />)
button.simulate('click')
assert.ok(callback.calledOnce)
}) I'm not suggesting that you should be doing this; what I took from #2991 is that it's an anti-pattern.
Right, but then why have an example in the docs with such a naive handler? I submitted this PR because I was led toward the pattern by that example. I also offered to add a warning instead of removing the example. |
I just want to avoid people doing silly things like browserHistory.push inside of an onEnter hook. (I've seen it attempted...) browserHistory usage should be thoughtful, that's all. Maybe the example should be of an actual lifecycle function instead of something opaque. |
Ah ha! Maybe we do export a |
That's a pretty contrived example that literally only comes up if you're using Enzyme, since React doesn't natively support simulating events on shallow rendered components. If you're running in Karma, I definitely don't agree that the example led you to the pattern that you chose – I think the |
@ryanflorence With e.g. async-props, can you access the async data in |
Enzyme is the wrapper I happen to use, but it seems like you'd want to test component methods regardless of framework, and folks are increasingly moving toward non-browser unit testing. Perhaps I'm wrong, but I don't think this type of situation is that uncommon.
I saw the example, wrote some code that errored, thought "oh! it makes sense that this breaks, but I wonder why they suggest doing this kind of thing?" and opened #2991. I didn't contrive the example; it was my experience as a user encountering the docs. I recognize the difference between the two examples, but I think it's an awfully large gotcha to go unexplained. I'm surprised by the hostility given that I opened this PR with the intention of improving the docs and offered to revise it with an explanatory warning instead.
That sounds great -- perhaps also with a comment explaining the nuance. Happy to submit another PR. |
Probably submitted that right as you started writing. Check #3027 😄 |
Per discussion in #2991, the second example is a fragile pattern. As @taion mentioned:
browserHistory
is undefined in non-browser environments, so accessingbrowserHistory.push
throws. It also relies on using the same history passed toRouter
, which may (conditionally) change.Let me know if you'd prefer adding a warning over removing the example entirely.