First couple things I thought about when migrating after reading the docs
So migrating my existing app wasn't as troublesome as I originally thought. First thing I did was take a look at my router and routes
and figure try to make a mental model of all the files where I had nested routes in the existing app because those components/containers will contain {this.props.children}
. So I need to replace those with the nested <Match />
components.
So just to give an example:
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={LandingContainer}/>
<Route path="profile/:username" component={UserProfileContainer}/>
<Route path="reviews/:username" component={ReviewsContainer} />
<Route path="userhome" component={UserHome}/>
<Route path="item/:id" component={ItemPageContainer}/>
<Route path="event/:id" component={EventPageContainer} />
<Route path="listings(/:searchTerm)" component={ListingsContainer}/>
<Route path="checkout" component={CheckoutContainer} />
<Route path="dashboard" component={Dashboard}>
<IndexRoute component={DashCartContainer}/>
<Route path="dashtrades" component={DashTradesContainer}/>
<Route path="dashmanageitems" component={DashManageItemsContainer}/>
<Route path="dashmanageevents" component={DashManageEventsContainer}/>
<Route path="dashorderhistory" component={DashOrderHistory}/>
<Route path="dashevents" component={DashEventsContainer}/>
<Route path="dashtracking" component={DashTracking}/>
<Route path="dashshipinfo" component={DashShipInfoContainer}/>
<Route path="dashbillinfo" component={DashBillInfoContainer}/>
<Route path="dashcustomerservice" component={DashCustomerServiceContainer}/>
<Route path="dashaccountsettings" component={DashAccountSettings}/>
</Route>
</Route>
...
<Route path="*" status={404} component={NotFound}/>
</Router>
<Router>
<div>
<Match pattern="/" component={LandingContainer}>
<Match path="profile/:username" component={UserProfileContainer}/>
<Match path="reviews/:username" component={ReviewsContainer} />
<Match path="userhome" component={UserHome}/>
<Match path="item/:id" component={ItemPageContainer}/>
<Match path="event/:id" component={EventPageContainer} />
<Match path="listings(/:searchTerm)" component={ListingsContainer}/>
<Match path="checkout" component={CheckoutContainer} />
<Match path="dashboard" component={Dashboard} />
<Miss component={NotFound}/>
</div>
</Router>
Couple things change from v2
to v4
:
-
No longer need to add history prop on
<Router />
-
Need to wrap children of
<Router />
within a<div />
(mistake that I made initially to not wrap in<div />
Will throw error) -
<Route />
-><Match />
-
<Match />
takes apattern
prop to match to a url like/RRv4IsGreat
-
Dedicated component to catch invalid not "registered" urls with
<Miss />
-
I removed all nested routes. This is because since now all of the components that are exported from ReactRouter are really just components you can just put components down a container component as its children and it works like magic!
So instead of having all nested routes inside a "Main" router you can just put them in a container like:
class Dashboard extends React.Component {
render () {
return (
<div>
<DashMenu pathname={this.props.pathname}/>
<Match exactly pattern={this.props.pathname} render={() => <DashCartContainer />}/>
<Match pattern={`${this.props.pathname}/dashtrades`} component={DashTradesContainer}/>
<Match pattern={`${this.props.pathname}/dashmanageitems`} component={DashManageItemsContainer}/>
<Match pattern={`${this.props.pathname}/dashmanageevents`} component={DashManageEventsContainer}/>
<Match pattern={`${this.props.pathname}/dashorderhistory`} component={DashOrderHistory}/>
<Match pattern={`${this.props.pathname}/dashevents`} component={DashEventsContainer}/>
<Match pattern={`${this.props.pathname}/dashtracking`} component={DashTracking}/>
<Match pattern={`${this.props.pathname}/dashshipinfo`} component={DashShipInfoContainer}/>
<Match pattern={`${this.props.pathname}/dashbillinfo`} component={DashBillInfoContainer}/>
<Match pattern={`${this.props.pathname}/dashcustomerservice`} component={DashCustomerServiceContainer}/>
<Match pattern={`${this.props.pathname}/dashaccountsettings`} component={DashAccountSettings}/>
</div>
);
}
}
Couple things you may notice here:
-
The first Match you see there has a prop called
render
which you can kind of think of as the<IndexRoute />
and it will render what ever component you pass it when it hits the "index" route of the nested view. -
You don't need to wrap the nested views within a
<Router />
. (Probably since the original router passes down props or context) -
I can render other components along side the
<Match />
components! Like a menu for my nested view. -
I pass the
pathname
prop down to the menu component, specifically for the<Link />
Found that its super helpful and easy in v4
to get access to the pathname and location because in v2 you had to use withRouter or something like that (not sure on the name because I began using react-router-redux
so that I could just pull of props, among other reasons).
My Links didn't really change much, only real changes we're changing the to
prop to take the props.pathname instead of the one I used to get from react-router-redux:
<div className={css(styles.DashTabs)}>
<ul className={css(styles.tabList)}>
<Link activeClassName={css(styles.activeTab, styles.noLeft)} to={`${props.pathname}`} activeOnlyWhenExact={true} className={css(styles.tab, styles.noLeft)}>Item</Link>
<Link activeClassName={css(styles.activeTab)} to={`${props.pathname}/dashtrades`} className={css(styles.tab)}>Trades</Link>
<Link activeClassName={css(styles.activeTab)} to={`${props.pathname}/dashmanageitems`} className={css(styles.tab)}>Manage Item</Link>
...
</ul>
</div>
Aside from that the rest of my app stayed unchanged.
The change from v2 to v4 honestly felt really really really good. Because it felt like the surface of what react-router should do shrunk dramatically. This for me personally was awesome! Because I for the most part rarely/never used anything but the routing from react-router. Also you can treat them like regular components and throw <Match />
in any component whenever you want instead of having this one giant <Router />
. My teammates and I didn't feel it was really that painful.
We will soon remove react-router-redux
from our project because one of my teammates we're telling me that we can programmatically route with v4
by hooking into <BrowserRouter />
onPush
prop which is awesome 🤘. I think hes writing an HOC to do this but hes actually currently working on it at the moment.
Im no expert of React-Router, I just saw the new API and saw some people really hating on it on twitter and wanted to see how bad it would actually be to actually migrate to it without speculating. Turns out not so bad! The migration took about 15-25 minutes tops. We we're able to keep all our Auth and Search Logic exactly the same! Big thank you to @ryanflorence & @mjackson for v4! Looking forward to opensourcing and contributing to some addons that my teammates and I were working on at Stela today!
looking forward to see "hooking into onPush prop which is awesome" this gist! tnx