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
Related
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.
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.
It seems like react router does not work with redux, clicking the link in App component successfuly add '/search' to the URL but it does not navigate to the search page, the navigation only happens after i refresh the page not after clicking the link, so what is the problem here??
Here are my two components
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import * as BooksAPI from './BooksAPI';
import registerServiceWorker from './registerServiceWorker';
import { createStore, applyMiddleware } from 'redux';
import { bookReducer } from './reducers/BookReducer';
import thunk from 'redux-thunk';
import {BrowserRouter as Router} from 'react-router-dom';
const middleware = [thunk];
const store = createStore(bookReducer, [], applyMiddleware(...middleware));
ReactDOM.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
App.js
import React, { Component } from 'react';
import { connect} from 'react-redux'
import BookShelf from './components/BookShelf'
import AllShelves from './components/AllShelves'
import Header from './components/Header';
import SearchPage from './components/SearchPage';
import * as BooksAPI from './BooksAPI';
import { Route } from 'react-router-dom';
import { Link } from 'react-router-dom';
import './App.css';
class App extends Component {
componentWillMount() {
this.props.fetchBooks();
}
render() {
console.log(this.props.books)
return (
<div className="App">
<Header />
<Route exact path="/" render={(props) => <AllShelves />} />
<Route path="/search" render={(props) => <SearchPage />} />
<div className="open-search">
<Link to="/search" />
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
books: state
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchBooks: () => {
BooksAPI.getAll().then(books => dispatch({
type: 'FETCH_BOOKS',
books
}))
},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
So why clicking link doesn't cause navigation to the search page and only add '/search' to the URL.
You might need to apply withRouter to make it work.
import {withRouter , BrowserRouter as Router} from 'react-router-dom';
// your code here
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
I recommend to to read the official documentation on how to integrate React Router with Redux
https://reacttraining.com/react-router/web/guides/redux-integration
I am new to React Js.
Everything works fine until I am trying to do action creator in ReactJs.
I know that there are other questions(posts) related to the title,however , I cannot find to solve my problem. Please Help me!
Here is my index.js
import 'materialize-css/dist/css/materialize.min.css';
import React from 'react';
import ReactDOM from 'react-dom';
import { provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import reduxThunk from 'redux-thunk';
import App from './components/App';
import reducers from './reducers';
import connect from 'react-redux/lib/connect/connect';
// create reducer
const store = createStore(reducers, {}, applyMiddleware(reduxThunk));
// Render the App in the HTML root element which is inside public foler
ReactDOM.render(
//Provier is to handle redux store actions
<provider store = { store }><App/></provider> ,
document.querySelector('#root')
);
Here is my App.Js
import React,{ Component } from 'react';
import { BrowserRouter, Route} from 'react-router-dom';
import { connect } from 'react-redux';
import * as actions from '../actions';
import Header from './Header';
const dashboard = () => <h2>DashBoard</h2>
const surveyNew = () => <h2>SurveyNew</h2>
const landing = () => <h2>Landing</h2>
class App extends Component {
//Call Action Creaters before View is Up
componentDidMount() {
this.props.fetchUser();
}
render () {
return (
<div className="container">
<BrowserRouter>
<div>
<Header/>
<Route exact path="/" component = {landing} />
<Route exact path = "/surveys" component = {dashboard}/>
<Route path = "/surveys/new" component = {surveyNew} />
</div>
</BrowserRouter>
</div>
);
}
};
export default connect(null, actions)(App);
Any help would be appreciated, Sirs. Thank You
It is with a capital "p" in "Provider". Try like that:
import { Provider } from 'react-redux';
...
<Provider store={store}><App/></Provider> ,
I'm having an issue in where by I switch routes, and the value of a property in my store is reverting back to it's original state. I'm using react 16 with react router v4.
I'm also noticing that the entire App component rerenders when I change routes. That seems over the top. It's running mapStateToProps and mapDispatchToProps every time. I'm noticing the state passed into mapStateToProps is always empty too.
I'm very puzzled.
main file
import React from 'react';
import { render } from 'react-dom';
import { connect } from 'react-redux';
//install routing deps
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store'
import App from './components/App';
render(
<Provider store={store}>
<BrowserRouter>
<App/>
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
store
import { createStore, compose, applyMiddleware} from 'redux';
import rootReducer from './reducers/index';
const defaultState = { count: 0 };
const enhancers = compose(
window.devToolsExtension ? window.devToolsExtension() : f => f,
);
const store = createStore(rootReducer, defaultState, enhancers);
//adds hot reload for changes to reducer
if(module.hot){
module.hot.accept('./reducers', ()=>{
const nextRootReducer = require(`./reducers/index`).default;
store.replaceReducer(nextRootReducer);
});
};
export default store;
App component
import React, { Component } from 'react';
import { Route, Switch, Redirect, Link } from 'react-router-dom';
import { BrowserRouter, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actionCreators from '../actions/actionCreators';
class App extends Component {
constructor() {
super();
};
render() {
return (
<div>
main
<a href='/info'>info</a>
<Switch>
<Route exact path="/" render={() => <h1>kawaii world</h1>} />
<Route exact path="/info" render={() => <h1>v kawaii world ;)</h1>} />
</Switch>
</div>
);
};
};
function mapStateToProps(state) {
return {
count: state.count
};
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch);
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
If you make use of tag a literally you are saying that you are willing to go to another page but in react apps that's not the case. In react you navigate from one component to another.
So to fix your issue you need to do this:
import { BrowserRouter, Link, withRouter } from 'react-router-dom';
class App extends Component {
render() {
return (
<div>
<Link to="/">Main</Link>
<Link to="/info">Info</Link>
<Switch>
<Route exact path="/" render={() => <h1>kawaii world</h1>} />
<Route exact path="/info" render={() => <h1>v kawaii world ;)</h1>} />
</Switch>
</div>
);
};
};