Issue implementing ConnectedRouter with react-router v4 upgrade - reactjs

I upgraded to use react-router v4 (rr-v4) and read that react-router-redux has been deprecated and for rr-v4 to use connected-react-router. In doing so I now get the following error:
The prop location is marked as required in ConnectedRouter, but
its value is undefined.
I can't seem to figure out what I've done wrong. I have quite a bit of code so I'm going to try and share what is relevant:
rootReducer:
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router'
import { reducer as oidcReducer } from 'redux-oidc';
...
const rootReducer = (history) => combineReducers({
routing: connectRouter(history),
oidc: oidcReducer,
...
export default rootReducer;
store.js:
import { createStore, applyMiddleware, compose } from 'redux';
import { routerMiddleware } from 'connected-react-router'
import { createBrowserHistory } from 'history'
...
export const history = createBrowserHistory()
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const initialState = {};
const createStoreWithMiddleware = composeEnhancers(
applyMiddleware(loggerMiddleware, routerMiddleware(history), thunkMiddleware)
)(createStore);
const store = createStoreWithMiddleware(rootReducer(history), initialState);
...
export default store;
index.js:
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { OidcProvider } from 'redux-oidc';
import store, { history } from './store';
import { App } from './App';
import userManager from './_helpers/userManager';
import { ErrorBoundary } from './_components/ErrorBoundary';
import "./web.config";
render(
<ErrorBoundary>
<Provider store={store}>
<OidcProvider store={store} userManager={userManager}>
<App history={history} />
</OidcProvider>
</Provider>
</ErrorBoundary>,
document.getElementById('app')
);
App.js:
import React from 'react';
import { ConnectedRouter } from 'connected-react-router'
import { Route, Switch } from 'react-router-dom';
...
class App extends React.Component {
constructor(props) {
super(props);
const { dispatch } = this.props;
}
...
render() {
const { history } = this.props;
return (
<ConnectedRouter history={history}>
<div>
<Route path="/" render={() => (<div>HOME</div>)} />
<Route path="/test" render={() => (<div>TEST</div>)} />
</div>
</ConnectedRouter>
);
}
}

The key under your rootReducer must be router, not routing.

Related

MapStateToProps not working inside component but Redux Devtools shows data

Cart inside the Cart Component is showing undefined, I tried with class and it says the same, none of my reducers are working with connect, Redux DevTools shows them all with no problem, component dev tool shows no props.
When using useSelector I get the state with no problem, but I have to use Connect for this.
this is my reducers file:
import { cartReducer } from "./cartReducer";
import { productsReducer } from "./stockReducer";
import { combineReducers } from "redux";
export const rootReducer = combineReducers({
cart : cartReducer,
products : productsReducer,
});
this is my store file:
import { createStore } from "redux";
import {rootReducer} from "../reducers/index";
const store = createStore(
rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store;
this is my component file:
import React from "react";
import { connect } from "react-redux";
const mapStateToProps = (state) => {
return {
cart: state.cart,
};
};
export function Cart({ cart }) {
console.log(cart);
return (
<div className="cart-detail">
<p>Cart</p>
</div>
);
}
export default connect(mapStateToProps, null)(Cart);
this is my Redux DevTools:
This is my App.js
import React from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import { FrontStore } from "./components/FrontStore";
import { Cart } from "./components/Cart";
export default function App() {
return (
<Router>
<div>
<nav>
<ul></ul>
</nav>
<Switch>
<Route path="/">
<FrontStore />
<Cart />
</Route>
</Switch>
</div>
</Router>
);
}
This is my index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from "react-redux";
import store from "./store/index";
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
)
Here you are importing non-default export which is not connected with the redux store. fix the import of the Cart component as below.
import Cart from "./components/Cart";
OR
Remove the export in Cart Function and remove the default in the connect
import React from "react";
import { connect } from "react-redux";
const mapStateToProps = (state) => {
return {
cart: state.cart,
};
};
function Cart({ cart }) {
console.log(cart);
return (
<div className="cart-detail">
<p>Cart</p>
</div>
);
}
export connect(mapStateToProps, null)(Cart);

Share history between react-router v4 with multiple ReactDOM.render

Need help with sharing history between two ReactDOM.render conmonent. I did it with Redux but no lack with react-router v4.
Code: index.js -> firs ReactDOM.render
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {AppContextProvider} from './context';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import reducerReducer from "./store/reducers/reducer";
import mapReducer from './store/reducers/map';
import {BrowserRouter} from "react-router-dom";
import thunk from 'redux-thunk';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const rootReducer = combineReducers({
reducer: reducerReducer,
map: mapReducer
});
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)));
ReactDOM.render(
<Provider store={store}>
<AppContextProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</AppContextProvider>
</Provider>,
document.getElementById('root')
);
Code: Map.js -> second ReactDOM.render
const popUpHTML = (
<Provider store={store}>
<Router history={createBrowserHistory}>
<PopUpClick
name={name}
img={img}
id={id}
/>
</Router>
</Provider>
);
const addPopup = (popUpHTML, coordinates) => {
const el = document.createElement('div');
// el.className = "marker";
ReactDOM.render(popUpHTML, el);
const mapboxGlPopup = new mapboxgl.Popup({
closeButton: false,
offset: 16,
anchor: 'top'
}).setDOMContent(el)
.setLngLat(coordinates)
.addTo(map);
}
addPopup(popUpHTML, coordinates);
So I need to get on click same URL history, now i gor just URL replace.
This is my rendered Components, and they are two whole new instance:
React Component in dev tools.

Error: Could not find router reducer in state tree, it must be mounted under "router"

The above error occurred in the component:
in ConnectedRouter
in ConnectedRouterWithContext
in ConnectFunction
in Provider
I am stuck in a error saying Could not find router reducer in state tree, it must be mounted under "router"
This is my store.js file.....
import storage from 'redux-persist/es/storage';
import { apiMiddleware } from 'redux-api-middleware';
import { applyMiddleware, createStore } from 'redux';
import { createFilter } from 'redux-persist-transform-filter';
import { persistReducer, persistStore } from 'redux-persist';
import { routerMiddleware } from 'react-router-redux';
import rootReducer from './redux/reducers';
import { combineReducers } from 'redux-immutable';
import { connectRouter, RouterState } from 'connected-react-router/immutable';
export default (history) => {
const persistedFilter = createFilter(
'auth', ['access', 'refresh']);
const reducer = persistReducer(
{
key: 'polls',
storage: storage,
whitelist: ['auth'],
transforms: [persistedFilter]
},
rootReducer)
const store = createStore(
reducer, {},
applyMiddleware(
apiMiddleware,
routerMiddleware(history))
)
persistStore(store)
return store
}
This is how my index.js is
const history = createHistory()
const store = configureStore(history)
ReactDOM.render((
<Provider store={store}>
<ConnectedRouter history={history}>
<Router>
<Switch>
<Route exact path="/login/" component={Login} />
<PrivateRoute path="/" component={App}/>
</Switch>
</Router>
</ConnectedRouter>
</Provider>
), document.getElementById('root'));
At first, you should add a router in the reducer.
const createRootReducer = (history) => combineReducers({
router: connectRouter(history),
... // rest of your reducers
})
export default createRootReducer
If you're using react-router-dom#5.x.x then you should use history#4.10.1 because the latest version of history (v5) only works with react-router-dom#6.x.x

How to get ReactRouter Props , while using Redux

App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
// import browserRoute
import { BrowserRouter, Switch, Route, Link } from 'react-router-dom'
// redux
import Todo from './todo/Todo';
import Login from './todo/Login';
import Home from './todo/Home';
import Callender from './Callender/Callender'
import WhetherData from './Callender/CallenderComponent'
import { localstoreExport } from './index';
export default class App extends Component {
render() {
return (
<BrowserRouter>
< Switch>
<Route path="/todo">
<Todo />
</Route>
<Route path="/login">
<Login />
</Route>
<Route path ="/callender">
<Callender />
</Route>
<Route path="/climateshow" component ={WhetherData}/>
<Route exact path="/" component={Home}/>
</Switch>
</BrowserRouter>
</Provider>
)
}
}
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// Redux
import { createStore,combineReducers,applyMiddleware,compose } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
// import reducer
import todoReducer from './store/reducers/rootReducer';
import whetherReducer from './store/reducers/callender'
// combine the Reducer
const rootReducer = combineReducers({
todoReducer,
whetherReducer
})
// chrome extension helper
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// create a store
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)));
export const localstoreExport = store;
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
Callender.js
import React, { Component } from 'react';
import { DatePicker, DatePickerInput } from 'rc-datepicker';
import 'rc-datepicker/lib/style.css';
import axios from 'axios'
import { connect } from 'react-redux';
// redux components
import { getDataFromApi } from '../store/actions/callender'
class Callender extends Component {
state = {
totalDate:''
}
// These is the complete code for getting the response from version 2 of api
onChange = (event) =>{
console.log(event);
this.setState({
totalDate:event
})
this.props.getWhetherData()
{console.log(this.props.whetherData)}
}
render() {
const date = '2015-06-26';
return (
<div>
<DatePicker onChange={this.onChange} value={date} />
{this.props.whetherData? console.log(this.props.history): null}
</div>
)
}
}
const mapStateToProps = state =>{
return {
whetherData: state.whetherReducer.whetherData
}
}
const mapDispatchToProps = dispatch =>{
return {
getWhetherData : () => dispatch(getDataFromApi())
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Callender);
1)In the following code I have written my Routes, in App.js file and created store in Index.js
2) In Callender.js i want to push my route to whether data end Point so i am trying to see the this.props.history it is showing undefined
3) so i tried to see my props by this.props Now it is showing me the redux props so i realized that
my router props are getting overridden by redux props
4) how to use history push while using redux
You can wrap your component with withRouter.
import { withRouter } from "react-router";
export default connect(mapStateToProps,mapDispatchToProps)(withRouter(Callender));
You can find detailed example here.

Why there is no history prop in my "connected" components?

I just migrated to react-router, react-router dom v4.3.1, installed history v4.9. Earlier, all my components which were connected to the store, got router props. Now, they say that there must be a history prop. However, I dont get it anywhere, especially in App component.
Root:
import React, { Component } from "react";
import { Provider } from "react-redux";
// import { BrowserRouter, Route, browserHistory, Switch } from "react-router";
import { BrowserRouter as Router, Route, Switch} from "react-router-dom";
import { hot } from 'react-hot-loader'
import { ConnectedRouter } from 'connected-react-router'
import configureStore, {history} from '../store/configureStore'
import App from "./App";
import Startpage from "./startpage";
import PatientSearch from "./routes/patient/patientSearch";
import Technician from "./routes/technician/technician";
import Notes from "./routes/notes/notes";
import DeliveryReports from './routes/admin/deliveryReports/reports'
const store = configureStore(/* provide initial state if any */)
class Root extends Component {
render() {
console.log('propsroot', this.props)
return (
<Provider store={store}>
<ConnectedRouter history={history}>
{/*<Router onUpdate={() => window.scrollTo(0, 0)}>*/}
<App>
<Switch>
<Route exact path="/" component={Startpage} />
<Route
component={PatientSearch}
path="/patient/search"
/>
<Route
component={Technician}
path="/technician"
/>
<Route
component={Notes}
path="/notes"
/>
<Route
component={DeliveryReports}
path="/delivery_reports"
/>
</Switch>
</App>
{/*</Router>*/}
</ConnectedRouter>
</Provider>
);
}
}
export default hot(module)(Root)
ConfigureStore:
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { connectRouter } from 'connected-react-router'
import promiseMiddleware from '../middleware/promiseMiddleware';
import loggerMiddleware from 'redux-logger';
import * as reducers from '../reducers/';
import { reducer as formReducer } from 'redux-form'
import app from '../reducers/app'
import {createBrowserHistory} from "history";
export const history = createBrowserHistory()
const reducer = combineReducers({...reducers.default, router:connectRouter(history), form:formReducer });
const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware,
promiseMiddleware
)(createStore);
export default function configureStore(initialState) {
const store = createStoreWithMiddleware(
reducer,
initialState,
window.devToolsExtension && window.devToolsExtension()
);
if (module.hot) {
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers/index');
store.replaceReducer(nextRootReducer);
});
}
return store;
}
In App component I render routes with {children} props
The history prop is provided by your provider. To serialize it in you component's props use the withRoute HOC

Resources