-
Notifications
You must be signed in to change notification settings - Fork 801
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
Get this working properly with React Router #249
Comments
I ran into this today when using react router properly for the first time, and was surprised that no-one had tackled this before. How do all those people work with a Router that won't hot reload without getting really frustrated? Ideally, the proper fix for this should be in resolving remix-run/react-router#2182 - bcause the warning here is just cheeky: https://github.com/reactjs/react-router/blob/master/modules/Router.js#L131 "Sorry, this looks like a declarative component but it's actually an imperative API call and we're doing to ignore your new routes!" I'll take my further comments / help over to that thread now 😄 |
Previous versions of React Hot Loader or React Transform used to wrap class in the proxy during its definition time, so this wasn’t much of an issue—the update would just never propagate up to the router. The current approach has many more upsides (e.g. works with functional components) but it now wraps components in |
Thanks for looking at it! |
I just had an idea I wanted to write down, not thought through heavily yet. What if instead of trying to patch Something along these lines: // Make a note of the Route component so we can detect it later
require('react-hot-loader/patch-router')(Route);
// ...
React.createElement = function(type, props, ..children) {
// as well as all the other stuff
// When we see a Route, proxy its component
if (type == Route && props.component) props.component = proxy(props.component)
// ...
} This sort of approach would ensure that the component is proxied whenever the routes list is "rendered" even though those Exactly how and when to do this is up for debate, but I think the general idea of opt-in to detecting Route and converting those components to proxies should sort things out. |
Thanks for the idea! I added this to |
Will have to figure out some way to get this working with |
I feel this is out of scope of this hack and should be fixed in remix-run/react-router#2182. |
@gaearon This may be a hack, but passing // Root.js
import React, { Component } from 'react';
import { Provider } from 'react-redux'
import { browserHistory, Router} from 'react-router'
import configureStore from './store/configureStore'
import routes from './routes'
export default class Root extends Component {
render() {
const store = configureStore()
return (
<Provider store={store}>
<Router history={browserHistory} routes={routes} key={Math.random()}/>
</Provider>
);
}
} |
@jaredpalmer As far as I can see, this means a different component is mounted every time, so the state of any children components is destroyed. If this works well for you (e.g. you don’t use local state a lot), you can remove React Hot Loader and just use Webpack HMR API without it. |
Aside from the annoying warning, should be fixed in |
Is there a working example for react-router somewhere? |
@burkhardr Root.jsexport default function Root() {
return (
<Router component={App}>
...
</Router>
)
} index.jsTake this file and replace |
Sorry if this is a dense question, but is |
It’s expected to work (as in, I don’t see why it wouldn’t), but I have not tested it, so issues might still exist. |
Is React Router supposed to work with beta.2 with no errors? If so, what is the way of having it work? The hot reload works for me, but I keep receiving the error in console. The error is:
[EDIT] The only way to make it work is via setting |
It is not an error, it is a warning. There is no harm in it. Yes, it’s expected to appear until React Router fixes remix-run/react-router#2182, but you don’t need to worry about it.
This does not make it work. You are forcing the root component to remount, thereby losing all the local state. If this works well for you, you don’t need React Hot Loader at all because its only purpose is to preserve the local state. |
Thanks @gaearon , I already got accustomed to my red friend in the console;). Just for the peace f mind it would be great to have warning displayed as warning, not error, but that's no biggie. I'll wait for RR fix. Thanks for your answer! |
👍 |
EDIT: After pulling my repo and doing a clean run, I cannot reproduce the effect unfortunately. Perhaps I'm missing something, but I seem to have things working without using @jaredpalmer's I'm using:
The only change I made was instead of using a random key, I set the router's key to a static string. Basically as you see here: https://github.com/jaredpalmer/react-production-starter/blob/master/client/index.js#L39 Mind you, I'm using async routes using Webpack 2's native module dynamic loading with I'll post my |
Defining a static |
@frankleng You're right. It seems it was just a fluke that I cannot reproduce on a clean setup. EDIT: @frankleng Trying your method, the routes never change after updating. Does it not warn you when adding or removing a route, then navigating to it using |
@chase thanks for catching that. might've missed it when I copy and pasted. local state is is maintained and not seeing any warnings at the moment. |
After quite a bit of searching, I found @dferber90's React Router with RHL3 compatibility table Using My setup is more or less like this: refEqualRootRoute.js export default {} routes.js import App from './App'
import SomeContainer from './SomeContainer'
import refEqualRootRoute from './refEqualRootRoute'
export default Object.assign(refEqualRootRoute, {
component: App,
path: '/',
childRoutes: [
{
path: '/SomePath',
component: SomeContainer,
},
],
indexRoute: {component: App},
}); Root.js import React from 'react';
import routes from './routes';
import {Router, browserHistory} from 'react-router/es6';
const Root = ({store}) => (
<Provider store={store}>
<Router history={browserHistory} routes={routes} />
</Provider>
);
Root.propTypes = {
store: PropTypes.object.isRequired,
};
export default Root; index.js import {configureStore} from './store';
import rootSaga from './Sagas';
import Root from './Root';
const store = configureStore({});
let rootTask = store.runSaga(rootSaga);
const root = document.getElementById('app');
const render = () => {
ReactDOM.render(
<AppContainer>
<Root store={store} />
</AppContainer>,
root
);
};
render();
if (process.env.NODE_ENV === 'development') {
if (module.hot) {
module.hot.accept('./Sagas', () => {
rootTask.cancel();
rootTask = store.runSaga(rootSaga);
render();
});
module.hot.accept('./Root', render);
}
} |
thanks @calesce , that's good to know. I was refreshing the page anyway, so it's still an improvement for me. |
Is this issue still on the roadmap for RR3? |
@schickling It was tracked in remix-run/react-router#2182, but it looks like they want everyone to migrate to 4.0 as a solution, and the maintainers won't be doing major updates on 3.X. RR 2/3 mostly works with React Hot Loader as it currently stands, AFAIK the only issues are the console warning and |
Thanks for that clear wrapup @calesce! |
Anyone else having issues with RR3 and hot reloading? Normal entries reload fine but doesn't for me. I set them to the same component just to try things, and only the Route entry would hot reload it. Going to try migrating to RR4, but was curious if I'm alone on that issue. |
@Codelica I "solved" it like this, with routes in their own module: let routes = <Route>
// All your routes
</Route>
// Any update within the app will bubble up to this file
// We can't create a new <Route> element though, because Router won't accept
// updates to its routes prop.
// So we're passing the previous export from update to update to prevent Router from complaining
// The React components themselves will still update properly
if (module.hot) {
let oldRoutes = module.hot.data && module.hot.data.routes
if (oldRoutes) {
routes = oldRoutes
}
module.hot.dispose(function(data){
data.routes = routes
})
}
export default routes |
@chase is your method here above #249 (comment) still the recommended approach to handling redux-saga? |
@awitherow I wouldn't say it is recommended, as I haven't used it with RR4 and stopped using RHL due to flaky behavior. It would not hurt to try and then post your results, though. |
I just wanted to share this fairly dirty workaround for hot-reloading async routes. I know it's bad to call these lifecycle functions directly but it's working for now, is there any other reason why I shouldn't do it? hacky_router.jsximport React, {Component} from 'react'
import {Router, browserHistory} from 'react-router'
export default class HackyRouter extends Component {
componentDidMount(){
// componentWillReceiveProps just whines about changing the routes prop so this shuts that up
this.router.componentWillReceiveProps = function(){}
}
componentDidUpdate(prevProps){
if(prevProps.routes != this.props.routes){
// tear down and set up router internals again
this.router.componentWillUnmount()
this.router.componentWillMount()
}
}
render(){
return <Router ref={ref=>this.router = ref} history={browserHistory} routes={this.props.routes} />
}
} entry.jsximport React from 'react'
import {render} from 'react-dom'
import HackyRouter from './hacky_router'
import routes from './routes'
import {AppContainer} from 'react-hot-loader'
const root = document.getElementById('root')
render((<AppContainer><HackyRouter routes={routes} /></AppContainer>), root)
if (module.hot) {
module.hot.accept('./routes', () => {
// reload the routes file
let nextRoutes = require('./routes')
render((<AppContainer><HackyRouter routes={nextRoutes} /></AppContainer>), root)
})
}
|
We still reproduce the issue with react-router and redux, in the console we have |
Same here, it says
And configuration from here: https://webpack.js.org/guides/hmr-react/ |
Has there been any progress on this? Also getting a similar issue where the CSS hot reloads 🙌 however the WDS tells me the app is up to date, but no DOM changes are made.
|
@aaronatmycujoo react-router < 4 will not be supported, if you use it you can setup hot reload stuff in Webpack without React Hot Loader. Your app will be entirely refreshed when a change occurs. |
@theKashey I had tried everything.. my modules were rebuilding, but the page wouldn't update. Is there a working example for react-routera and redux somewhere? |
Good example will got help you - it should work out of the box. Better provider your example to play with. |
There is a hacky workaround in gaearon/react-hot-boilerplate#61 (comment) but it’s way too hacky. We should either implement this in remix-run/react-router#2182, or include some sort of hacky workaround right in this project so at least it’s on us. Special casing React Router doesn’t sound very great but it’s hugely popular and we can’t just not support it.
3.0.0-alpha.12
)The text was updated successfully, but these errors were encountered: