After enabling historyApiFallback in the webpack config file and restarting the server, when changing location pathname, the browser refreshes, causing outter elements to re-mount (what I mean is that, I can see it flash white and back to normal) whenre this should only happen for nested the.props.children. Hope this makes sense!
In my particular case, there's a <Navbar />
element that is always present at the top and a container that has the { this.props.children }. I wonder what's going on ?
App entrypoint:
import React from 'react';
import ReactDOM from "react-dom";
import { Router, browserHistory } from 'react-router';
import routes from './routes';
import { syncHistoryWithStore } from 'react-router-redux'
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import promise from 'redux-promise';
import reducers from './reducers';
import thunk from 'redux-thunk';
// const createStoreWithMiddleware = applyMiddleware(promise)(createStore);
// const store = createStoreWithMiddleware(reducers);
const store = createStore(
reducers,
applyMiddleware(thunk)
);
const history = syncHistoryWithStore(browserHistory, store);
ReactDOM.render(
<Provider store={ store }>
<Router history={ history } routes={ routes } />
</Provider>,
document.getElementById('app')
);
webpack config file:
var path = require("path");
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
historyApiFallback: true,
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/dev-server',
'./src/js/index.js'
],
output: {
path: __dirname + '/static',
filename: "index_bundle.js"
},
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loaders: ["react-hot-loader", "babel-loader"] },
{ test: /\.scss$/, loader: 'style!css!sass' },
{ test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader: 'file-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
template: __dirname + '/src/' + 'index.html',
filename: 'index.html'
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
resolve: {
root: path.resolve(__dirname),
extensions: ['', '.js'],
alias: {
"TweenLite": "src/libs/gsap/TweenLite",
"CSSPlugin": "src/libs/gsap/plugins/CSSPlugin"
}
}
};
main wrapper/container:
import React, { Component } from 'react';
import Navbar from '../containers/navbar';
import ModalWindow from '../components/modalWindow';
// include the stylesheet entry point
require('../../sass/app.scss');
class App extends Component {
render() {
return (
<div className="app">
<Navbar />
<main>
{ this.props.children }
</main>
<ModalWindow />
</div>
);
}
}
export default App;
router config file:
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './containers/app';
import InitialScreen from './containers/initialScreen';
import Reservation from './containers/reservation';
const routes = (
<Route path='/' component={ App }>
<IndexRoute component={ InitialScreen } />
<Route path='your-trolley' component={ Reservation } />
</Route>
);
export default routes;
So far, I think there's something wrong in the webpack dev config file. Any suggestions or hints are appreciated!
Random user asked how the location is changed, so here's the action:
export function fetchReservationData(reservation_code, onError) {
return (dispatch) => {
fetch(apiConfig.find_my_product)
.then(function(response) {
if (response.ok) {
response.json().then(function (data) {
if (data.trolley.length > 0) {
dispatch({ type: UPDATE_TROLLEY_DATA, payload: data });
// todo: use router-redux push instead
window.location.pathname = '/your-trolley';
} else {
dispatch({ type: TOGGLE_MODAL_WINDOW, payload: onError });
}
});
} else {
// todo: handle exception
console.log('Network response was not ok.');
dispatch({ type: TOGGLE_MODAL_WINDOW, payload: onError });
}
})
.catch(function (error) {
// todo: handle error
// handle it gracefully asked user to try again, if the problem keeps ocurring to
// talk with a staff member to report it to the backend team
console.log('There has been a problem with your fetch operation: ' + error.message);
dispatch({ type: TOGGLE_MODAL_WINDOW, payload: onError });
});
}
}
Here's were the problem is; If I change the app entry point it works:
import React from 'react';
import ReactDOM from "react-dom";
import { Router, browserHistory } from 'react-router';
import routes from './routes';
import { syncHistoryWithStore, routerMiddleware, push } from 'react-router-redux'
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import promise from 'redux-promise';
import reducers from './reducers';
import thunk from 'redux-thunk';
// const createStoreWithMiddleware = applyMiddleware(promise)(createStore);
// const store = createStoreWithMiddleware(reducers);
const store = createStore(
reducers,
applyMiddleware(thunk),
applyMiddleware(routerMiddleware(browserHistory))
);
const history = syncHistoryWithStore(browserHistory, store);
setTimeout(() => {
store.dispatch(push('/your-trolley'));
}, 3000);
ReactDOM.render(
<Provider store={ store }>
<Router history={ history } routes={ routes } />
</Provider>,
document.getElementById('app')
);
So now I'll need to be able to dispatch the push from the action as I did in the entry point. It's a bit confusing because I'm pasing a middleware to the store and then the store is sync with the browserhistory, I guess I'll need to pass the return value from applyMiddleware(routerMiddleware(browserHistory)) in both cases (createstore and sunchistorywithstore) ?!
Since you're using
react-router
and don't want the browser to reload the entire page everytime you switch to new url, It's important to use the<Link>
component provided byreact-router
or create your own version of the component.To link between different pages you can
And then you it in your
render
function, use it likeAnd if you want to programmatically redirect user to different url/location
Edit: If you want to Redirect using
push
method provided byreact-router-redux
, You can do something like this