Trying to hook up a React component to my Redux state, but I am getting the error:
Uncaught Error: Expected the reducer to be a function
Not quite sure where I am going wrong:
import React from 'react';
import { render } from 'react-dom';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from 'redux-promise';
import store, { history } from './store';
// Import components
import App from './components/App';
import Expenditure from './components/Expenditure';
import Income from './components/Income';
import Transactions from './components/Transactions';
import Single from './components/Single';
// import css
import css from './styles/style.styl';
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
const router = (
<Provider store={createStoreWithMiddleware(store)}>
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={Expenditure} />
<Route path="/income" component={Income} />
<Route path="/expenditure" component={Expenditure} />
<Route path="/transactions" component={Transactions} />
<Route path="/expenditure/:id" component={Single} />
<Route path="/income/:id" component={Single} />
<Route path="/transaction/:id" component={Single} />
</Route>
</Router>
</Provider>
);
render(router, document.getElementById('root'));
My rootReducer:
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import expenditure from './expenditure';
const rootReducer = combineReducers({
expenditure,
routing: routerReducer
});
export default rootReducer;
And my actionCreators.js:
import axios from 'axios';
export const FETCH_EXPENDITURE = 'FETCH_EXPENDITURE';
export function fetchExpenditure() {
const request = axios.get('/api/expenditure');
return {
type: FETCH_EXPENDITURE,
payload: request
}
};
Then in my component, I am using connect to pull in the Redux state as props with the following below the Expenditure react class:
function mapStateToProps(state) {
console.log('state');
return {
expenditure: state.expenditure.all
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Expenditure);
Any tips would be incredible :)
are you using applyMiddleware correctly?
the docs have it passing applyMiddleware to the createStore function, not the other way around. i also dont see you using your rootReducer anywhere at all
try changing
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
to something like
// import rootReducer from '/path/to/rootReducer.js';
const createStoreWithMiddleware = createStore(
rootReducer,
[ ... ], //=> initial state
applyMiddleware(ReduxPromise)
)
then change your router input to
<Provider store={createStoreWithMiddleware}>
...
</Provider>
Related
Here is my code:
store.js
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
(window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()) ||
compose
)
);
App.js
import React, { Component } from 'react';
import './sass/main.scss';
import { BrowserRouter as Router, Route } from "react-router-dom";
import Landing from './components/pages/Landing';
import { Provider } from "react-redux";
import store from "../src/store";
import Register from "./components/auth/Register";
import Login from "./components/auth/Login";
class App extends Component {
render() {
return (
<Provider store={store}>
<Router>
<div className="App">
<Route exact path='/' component={Landing}/>
<Route exact path="/login" component={Login}/>
<Route exact path="/register" component={Register}/>
</div>
</Router>
</Provider>
);
}
}
export default App;
I can't find where the problem is. I tried to debug it, but can't found what really make it those error. error: Uncaught TypeError: store.getState is not a function.
./src/App.js
Attempted import error: '../src/store' does not contain a default export (imported as 'store').
The first thing tried is adding a export default createStore but that bring up other error message saying Line 10: 'store' is assigned a value but never used and TypeError: store.getState is not a function
In your App.js you are trying to import store from "../src/store";. So system will try to import something from ../src/store.js but you never export any variable in that file.
You can update store.js to add export statement
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
(window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()) ||
compose
)
);
export default store;
I have a ConnectedRouter to which I wanted to add hashes to all the routes so I added the HashRouter component like this:
// #flow
import React from 'react';
import { Router, Route,Switch } from 'react-router'
import { HashRouter } from 'react-router-dom'
import { ConnectedRouter } from 'react-router-redux';
import { routerActions } from 'react-router-redux';
import { UserAuthWrapper } from 'redux-auth-wrapper';
import StudiesViewContainer from './components/views/studies/StudiesViewContainer';
import NotificationsViewContainer from './components/views/notifications/NotificationsViewContainer';
import UserView from './components/views/user/UserView';
import StudyViewContainer from './components/views/studies/StudyViewContainer';
import { getUser } from './reducers';
import LoginView from './components/views/login';
import NotFoundView from './components/views/notFound';
import ForbiddenView from './components/views/forbidden';
const UserIsAuthenticated = UserAuthWrapper({
authSelector: getUser,
redirectAction: routerActions.replace,
failureRedirectPath: '/',
wrapperDisplayName: 'UserIsAuthenticated'
});
const configRouter = (history: Object) => {
return () =>
<ConnectedRouter history={ history }>
<HashRouter>
<Switch>
<Route path="/studies" component={ StudiesViewContainer } />
<Route path="/study/:id" component={ StudyViewContainer } />
<Route path="/user" component={ UserView } />
<Route path="/notifications" component={ NotificationsViewContainer } />
<Route path="/forbidden" component={ ForbiddenView } />
<Route path="/not-found" component={ NotFoundView } />
<Route path="/" component={ LoginView } />
<Route path="*" component={ NotFoundView } />
</Switch>
</HashRouter>
</ConnectedRouter>
};
export default configRouter;
The problem is that when I do something like this:
push('studies')
The route does not add the hash and the new components are not rendered.
I added the browser history to my store, here is the configureStore file:
// #flow
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import createHistory from 'history/createBrowserHistory'
import { routerMiddleware } from 'react-router-redux';
import createSagaMiddleware from 'redux-saga'
import {
persistStore,
autoRehydrate,
createTransform
} from 'redux-persist';
import mainSaga from '../sagas';
import reducer from '../reducers';
const history = createHistory();
const routingMiddleware = routerMiddleware(history);
const sagaMiddleware = createSagaMiddleware();
// Remove error field from persisted auth substate
let authTransform = createTransform(
(inboundState, key) =>
key === 'auth' ?
{ ...inboundState, error: undefined }:
inboundState,
outboundState => outboundState,
{
whitelist: [
'auth',
'permissions'
]
}
);
const configureStore = (): Promise<*> => {
let middlewares = [routingMiddleware,thunk, sagaMiddleware ];
let composeEnhancers = compose;
if(process.env.NODE_ENV !== 'production') {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
}
const store = createStore(
reducer,
composeEnhancers(
applyMiddleware(...middlewares),
autoRehydrate()));
sagaMiddleware.run(mainSaga);
return new Promise(resolve => {
persistStore(
store, {
whitelist: ['auth', 'permissions'],
debounce: 500,
transforms: [
authTransform
]
},
() => resolve({ store, history })
);
});
};
export default configureStore;
Can anyone help me get the push working as expected?
I am using the following versions of router in package json:
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-router-redux": "next",
I had a similar problem, I solved it by using
import createHistory from 'history/createHashHistory'
instead of
import createHistory from 'history/createBrowserHistory'
Also added withRouter when exporting components as suggested in
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
I added the browser history to my store, here is the configureStore file:
Most likely that issue lies on difference between history-object, used in router, and proposed in redux state. Then history created in redux side const history = createHistory();, it seems that it had not linked with ConnectedRouter object, but it can't be followed by supposed code.
If valid history object is passed to ConnectedRouter, try to check that subsequent router actions are to intercepted with saga process or other middleware. Try to follow on emitting actions flow by https://github.com/gaearon/redux-devtools tool.
Also you can try to perform manual updating, by adding root component with full lifecycle (Inherited from React.Component class), and add there following code:
this.props.history.listen((location, action) => {
console.log("on route change");
});
Then you can discover had router state been changed, and if action is taken, just perform forceUpdate method in root component. Also consult this documentation: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
I have a problem:
Warning: Failed prop type: Invalid prop children of type object supplied to Provider, expected a single ReactElement.
I have searched for an answer for sometime now but can't resolve this. My version of react is 15.3.0.
thanks~
import React from 'react';
import ReactDom from 'react-dom';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute, hashHistory } from 'react-router';
import { syncHistoryWithStore, routerReducer } from 'react-router-redux';
import thunkMiddleware from 'redux-thunk';
import reducers from './redux/reducers';
import Entrance from './components/Entrance.jsx';
import EntranceNone from './components/EntranceNone.jsx';
import CreditPoints from './components/CreditPoints.jsx';
import CreditPrivilege from './components/CreditPrivilege.jsx';
import CreditPromote from './components/CreditPromote.jsx';
let reduxDevTool = null;
let combReducer = { app: reducers, routing: routerReducer };
let store = createStore(combineReducers(combReducer), applyMiddleware(thunkMiddleware));
const history = syncHistoryWithStore(hashHistory, store);
ReactDom.render(
<Provider store={store}>
<div>
<Router history={history}>
<Route path="/" component={ Entrance }></Route>
<Route path="/EntranceNone" component={ EntranceNone }></Route>
<Route path="/creditPoints" component={ CreditPoints }></Route>
<Route path="/privilege" component={ CreditPrivilege }></Route>
<Route path="/promote" component={ CreditPromote }></Route>
</Router>
</div>
</Provider>,
document.getElementById('app')
);
require('../less/entrance.css');
import { initRootFontSize,originDomin } from '../utils';
import React,{Component} from 'react';
import classNames from 'classnames';
import 'babel-polyfill';
import cookie from 'react-cookie';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as Actions from '../redux/action';
import { hashHistory ,Link } from 'react-router';
class Entrance extends Component {
constructor (props) {
super(props);
initRootFontSize();
this.state = {
agree:true,
submitFlag:false
};
}
handleAgreeMent(){
this.setState({agree:!this.state.agree});
}
componentDidMount(){
if(creditData.isOpenCreditService === "0"){
this.context.router.push('/');
}else{
this.context.router.push('/creditPoints');
}
}
componentDidUpdate(prevProps,prevState){
if(this.props.resCode && this.state.submitFlag){
if(this.props.resCode == "000"){
this.context.router.push('/creditPoints');
}else{
alert(this.props.resMsg);
}
}
}
handleClick(){
if(this.state.agree){
this.props.actions.fetchIsOpen();
this.setState({submitFlag:true});
}
}
render () {
return(
<div className="wrap">
<div className="credit-img"></div>
<div className="credit-cont">
<p className="credit-cont-up">xxx</p>
<p className="credit-cont-down">xxx</p>
</div>
<div className="credit-agree"><span className={classNames({icon: true, iconSelected: this.state.agree})} onClick={this.handleAgreeMent.bind(this)}></span><span className="credit-agree-cont">xxxxx</span></div>
<div className={classNames({button: true,bottonFalse:this.state.agree,submitFlag:this.state.submitFlag})} onClick={this.handleClick.bind(this)}>{this.state.submitFlag?'x':'xx'}</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
resCode: state.app.resCode,
resMsg: state.app.resMsg,
dataList: state.app.dataList
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch),
};
}
Entrance.contextTypes = {
router: React.PropTypes.object
};
export default connect(mapStateToProps, mapDispatchToProps)(Entrance);
I'm managing my React application route with react-router and react-router-redux.
I setting router with following configuration:
import {Provider} from 'react-redux'
import {Router, browserHistory} from 'react-router'
import {createStore, combineReducers} from 'redux'
import {routerReducer} from 'react-router-redux';
import {syncHistoryWithStore} from 'react-router-redux'
import Reducers from './reducers'; // contains all my reducers,
const store = createStore(combineReducers(
{...Reducers, routerReducer}
));
const history = syncHistoryWithStore(browserHistory, store);
const AppRoute = (
<Provider store={store}>
<Router history={history}>
<Route path='login' components={PageLogin}/>
<Route path='system' components={PageSystem}>
<Route path="profile" component={PageProfile}/>
</Route>
</Router>
</Provider>
);
export default AppRoute;
When I try dispatch any router function:
import React from 'react';
import {Link, Route} from 'react-router';
import {connect} from 'react-redux';
import {replace, push} from 'react-router-redux';
class SystemMenu extends React.Component {
constructor(props) {
super(props);
this.logout = this.logout.bind(this);
}
logout() {
this.props.logout();
}
render() {
return (
<ul className="system-menu">
<li className={this.isActual("/system/profile")}>
<Link to="/system/profile">Profile</Link>
</li>
<li className={this.isActual("/system/unit")}>
<Link to="/system/unit">Units</Link>
</li>
<li>
<button onClick={this.logout}>Logout</button>
</li>
</ul>
)
}
}
const mapStateToProps = (state) => {
return {
router: state.router,
actualPage: state.menu.actualPage
};
};
const mapDispatchToProps = (dispatch) => {
return {
logout() {
dispatch(push('/login'));
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(SystemMenu);
When I click que Link component, pages is changing, But when I click the Logout button to debug, is executing dispatch(push('/login')); line, but nothing has happening, and no occur any error in the console.
What I worse in the configuration?
I tried console.log the logout inside the mapDispatchToProps function, and returning logout is not defined
const mapDispatchToProps = (dispatch) => {
console.log(push, logout);
return {
logout() {
dispatch(push('/login'));
}
};
};
combineReducers should take an object as the first argument, like this:
const store = createStore(
combineReducers({
...reducers,
routing: routerReducer
})
)
You're giving it an Array instead.
I suspect the reason why push doesn't work is because the router reducer is not registered properly.
I resolved this problem.
This problem is occurring because I has not using react-routerredux` middleware, so when I dispatching, maybe is not updating browser URL by state.
Following my route configuration:
import {Provider} from 'react-redux'
import {Router, browserHistory} from 'react-router'
import {createStore, combineReducers, applyMiddleware} from 'redux'
import {routerReducer} from 'react-router-redux';
import {syncHistoryWithStore, routerMiddleware} from 'react-router-redux'
import Reducers from './reducers'; // contains all my reducers,
const middleware = [routerMiddleware(browserHistory)];
const store = createStore(combineReducers(Reducers), compose(
applyMiddleware(...middleware)
));
const history = syncHistoryWithStore(browserHistory, store);
const AppRoute = (
<Provider store={store}>
<Router history={history}>
<Route path='login' components={PageLogin}/>
<Route path='system' components={PageSystem}>
<Route path="profile" component={PageProfile}/>
</Route>
</Router>
</Provider>
);
export default AppRoute;
I have set up for Server Side rendering. However the code in server.js calling store.getstate() only gets my default initial state and not the state the client is. How can I fix this?
Server.js:
http://pastebin.com/u31cqaUh
Configurestore:
http://pastebin.com/7FXV6NDS
Root.js:
import React, {Component} from 'react';
import {Provider} from 'react-redux';
import configureStore from './store/configureStore';
import {Router, Route, hashHistory, browserHistory} from 'react-router';
import { syncHistoryWithStore, routerReducer } from 'react-router-redux';
import Routes from '../routes';
const store = configureStore(window.__INITIAL_STATE__);
delete window.__INITIAL_STATE__;
const history = syncHistoryWithStore(browserHistory, store)
export default class Root extends Component {
render() {
return (
<Provider store={store}>
<Router history={history} routes={Routes}>
</Router>
</Provider>
)
}
}