That's correct. There is no withRouter in this version. The API is completely different.
I've seen that. Any workaround to implement withRouter
in v4?
No, because you don't need to access it anymore. That's not how the API works in 4.0
Good. And let's say I need to access router.push inside my React code?
@timdorr Do I miss something?
Without seeing your particular use case, it's hard to tell. However, under the new paradigms of 4.0, you shouldn't have to reach out to imperative code. You should just render a <Redirect>
. Look at the auth example for guidance.
Hello! I have checked out auth example from docs and I'd like to summarize why withRouter
solution was better.
Here is what we had before in v2:
class Login extends React.Component {
login = () => {
auth.authenticate().then(
() => this.props.router.replace('/')
);
}
}
export default withRouter(Login);
And how it should be updated to use v4:
class Login extends React.Component {
state = {
shouldRedirect: false
}
login = () => {
auth.authenticate().then(
() => this.setState({shouldRedirect: true})
);
}
render() {
if (this.state.shouldRedirect) {
return <Redirect to="/" />;
}
}
}
export default Login;
Look, now there is more code that does exactly the same. Also in v2 you could change the current location whenever you want with a single line of code, now this logic is spread among the whole component and this probably causes a lot of frustration from developers.
add contextTypes: { router } and it's all yours, even wrap it up in your
own withRouter.
On Sat, Sep 17, 2016 at 9:34 AM Boris Serdiuk [email protected]
wrote:
Hello! I have checked out auth example from docs and I'd like to summarize
why withRouter solution was better.Here is what we had before in v2:
class Login extends React.Component {
login = () => {
auth.authenticate().then(
() => this.props.router.replace('/')
);
}
}export default withRouter(Login);And how it should be updated to use v4:
class Login extends React.Component {
state = {
shouldRedirect: true
}login = () => {
auth.authenticate().then(
() => this.setState({shouldRedirect: true})
);
}render() {
if (this.state.shouldRedirect) {
return;
}
}
}export default withRouter(Login);Look, now there is more code that does exactly the same. Also in v2 you
could change the current location whenever you want with a single line of
code, now this logic is spread among the whole component and this probably
causes a lot of frustration from developers.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/ReactTraining/react-router/issues/3847#issuecomment-247786797,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGHaNNtiDP9b_qqMKuKy4PDaBMc5Rd1ks5qrBaFgaJpZM4J8rp0
.
Well, that's good that I can write my own withRouter and solve this.
But this is contrary to @timdorr's answer:
No, because you don't need to access it anymore. That's not how the API works in 4.0
Can I think that access to the context via HOC is a recommended solution to simplify redirect logic when it is possible?
I am missing withRouter in the API as well. What if I have nested components far below the original Match component, but want to have a Link to a route below the current path.
Example:
/machines/{id} renders a MachineDetailsContainer. Somewhere in it's component subtree I have a component which should link me to /machines/{id}/logs, where only the logs of this specific machine are displayed.
I could solve this by either passing down the router props all the way from MachineDetailsContainer (which would lead to the ugly situation of components in the subtree only passing the props down without using them), or by passing only the id down and then building a new absolute route path /machines/${id}/logs
(not that nice either, since I'd have to change this route building if I move the main component).
Or is there any way to do this that I missed while reading the docs?
I hope its not just stubborness and I am still trying to get used to the new API approach, but its just odd that you have to render something to cause a state change.
Under the hood, it looks like Link does a transitionTo on the router, so why would that not imply that is how you should navigate between views?
Example to some of those questions above, i assume (and I may be completely wrong so forgive me), but if you say want to click a button to transition to another view, you have to
router is on context, you can use it.
On Mon, Sep 26, 2016 at 10:50 AM harryh [email protected] wrote:
I hope its not just stubborness and I am still trying to get used to the
new API approach, but its just odd that you have to render something to
cause a state change.Under the hood, it looks like Link does a transitionTo on the router, so
why would that not imply that is how you should navigate between views?Example to some of those questions above, i assume (and I may be
completely wrong so forgive me), but if you say want to click a button to
transition to another view, you have to
- Handle the button click.
- Do something that renders out a Redirect.
—
You are receiving this because you commented.Reply to this email directly, view it on GitHub
https://github.com/ReactTraining/react-router/issues/3847#issuecomment-249644143,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGHaNHSpzbjbiNsCu5rVCcyLjDkKL3Tks5quAXKgaJpZM4J8rp0
.
@ryanflorence i think part of my own confusion was the push from switching from using the context.router to using withRouter and really recommending that, so it my assumption was that you shouldn't mess with the context.router. My bad.
Also, do you still have to provide the contextTypes?
Also, there is this issue when assuming to use 'this.context' https://github.com/ReactTraining/react-router/issues/3903 - A comment and potential discussion about not using this.context
Re-opening this because Facebook still warns people against using context directly.
Want me to port the withRouter wrapper into 4.0? Should be pretty simple to do.
withRouter does the same thing anyhow and accesses the.context, doesn't it? I guess if it's generally agreed with you guys/gals that it is acceptable to do so and stops users from doing accessing themselves, it is probably the best option.
It seems even though the API is "different" as @timdorr said, it still uses withRouter underneath (like in the Link
comp) to do this. So it might be good to allow that to users as well.
Yes, but that's abstracted away from you, so you don't have to worry about it. That way, if the API were to change for some reason, then we could patch over those changes without you having to adjust your code at all.
Completely agreed @timdorr.
I'm not certain that withRouter
is the solution. Wanna think about it some more.
Another option is providing some router via react-router and decouples routing from a view. However, that is probably against your heart around the new API.
Regardless of withRouter or not, you either provide routing through props, or you import it in.
withRouter was the way to go before because it wasn't automatically there. I don't know what assumptions you should make about providing on the route automagically, so then that leaves you with providing an optional way to get it. If you want to stick with declarative nature of comps, you could also have a route match prop that will give the view the router or not and thus fully abstracting out any need to import something separate.
However, there are probably issues with where this logic goes and other things. I'll mull some things over and try out some and maybe make a PR to see if you guys like anything.
Any idea how to access goBack()
in v4? Doesn't seem to exist on context.router
.
Anyone wondering about goBack
and the other history methods, history
is actually exposed on the context by react-history.
import { propTypes } from 'react-history';
class App extends React.Component {
render() {
const { push } = this.context.history;
return <a onClick={() => push('/somewhere')}>Go</a>
}
}
App.contextTypes = {
history: propTypes.historyContext
};
@alisd23 Yep, that's correct. Maybe we should wrap up a withRouter
that also grabs history
off context?
@timdorr I think it is worthwhile, even though it's literally a 10 line function. It's common enough that people would be adding it to many of their projects - so we may as well give it them for free.
I'm trying to learn React-Router v4 and I'm really enjoying, so far. I see it as a paradigm shift and so I don't mind do things differently if there's sense on it. I think the given example was very contrived and unexplained, the transitioning states ( pending, rejected ) were completely ignored there, my suggestion would be:
export default class Login extends React.Component {
tryAuthenticate = () => {
this.setState({ auth: auth.authenticate() });
}
componentWillMount() {
this.tryAuthenticate();
}
render() {
// <Subscribe /> accepts a promise in `to`, renders pending until `.then` or `to` is changed.
// rejection causes `rejected` to be rendered, resolution causes `resolved` to be rendered
return (
<Subscribe
to={this.state.auth}
pending={<Spinner />}
resolved={<Redirect to="/" />}
rejected={() =>
/* Opportunity to retry with User Interaction */
<button onClick={this.tryAuthenticate}>It failed…try Again?</button>
}
/>
);
}
}
And yes, far more code, but here we have view flow completely explained and a reusable component for manage future values and composability.
What do we think withRouter
should pass down as props? I suppose the router
and history
context is a definite. I would also consider moving the location property out of history as a top level prop, because I think the current location is fairly important information.
The props from withRouter
would then look like this:
Thoughts?
Just to clarify: the only way to call goBack
is to manually include react-history?
@mbrevda see this comment - https://github.com/ReactTraining/react-router/issues/3847#issuecomment-252966037
React-history is already depended on by React-router, no need to install it
thanks @alisd23 its working for me now
React-history is already depended on by React-router, no need to install it
Importing extraneous packages is bad practice. If the goal is to import react-history
through react-router
, I would think react-router
would provide something like:
import { history } from 'react-router'
// or
import history, { propTypes } from 'react-router/history'
This way, we aren't importing our dependencies' dependencies.
follow #4044
Most helpful comment
Hello! I have checked out auth example from docs and I'd like to summarize why
withRouter
solution was better.Here is what we had before in v2:
And how it should be updated to use v4:
Look, now there is more code that does exactly the same. Also in v2 you could change the current location whenever you want with a single line of code, now this logic is spread among the whole component and this probably causes a lot of frustration from developers.