I am trying to dispatch another action inside one async action creator. However, when I am using dispatch function provided by redux-thunk middleware, it is throwing Uncaught TypeError: dispatch is not a function
error.
Below are the files for more help
store/store.dev.js
use strict';
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from '../reducers';
import ReduxThunk from 'redux-thunk';
export default function configureStore(initialState = {}) {
const store = createStore(rootReducer, initialState, applyMiddleware(ReduxThunk));
console.log('store returned', store);
return store;
}
src/index.js
'use strict';
import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { hydrate } from 'react-dom';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import configureStore from './store';
import App from './containers/App.js';
import routes from './routes/index.js';
hydrate(
<Provider store={configureStore()}>
<BrowserRouter>
{renderRoutes(routes)}
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
reducer
'use strict';
import { LOGIN_SUBMITTED, LOGIN_COMPLETED } from '../constants/ActionTypes.js';
const loginSubmitReducer = (state = [], action) => {
console.log('in reducer');
switch (action.type) {
case LOGIN_SUBMITTED:
console.log('login submitted case');
return Object.assign({}, state, {
loginSubmitted: true
});
case LOGIN_COMPLETED:
console.log('login completed case');
return Object.assign({}, state, {
loginCompleted: true
});
default:
console.log('in default case');
return {
a:1
};
}
}
export default loginSubmitReducer;
containers/App.js
'use strict';
import React from 'react';
import { loginCompleted, loginSubmitted } from '../actions';
import { createStructuredSelector, createSelector } from 'reselect';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Header, ButtonDemo, LoginForm } from '../components';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
class App extends React.Component {
constructor(props, context) {
super(props);
this.state = {
appState: {
entry: 'yes'
}
}
console.log('props in App constructor', props);
console.log('context in App constructor', context);
this.newFunc = this.newFunc.bind(this);
}
newFunc () {
console.log('props', this.props);
}
render() {
console.log('props in main App', this.props);
console.log('Actions', this.props.actions);
console.log('context in App', this.context);
// this.props.actions.loginCompleted();
const muiTheme = getMuiTheme({
lightBaseTheme
});
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div>
<Header />
<LoginForm
appstate = {this.props.appState}
dispatchAction = {this.props.actions}
/>
</div>
</MuiThemeProvider>
);
}
}
// const mapStateToProps = createStructuredSelector({});
const mapStateToProps = (state) => {
return { appState: state.loginSubmitReducer };
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({ loginCompleted, loginSubmitted }, dispatch)
};
// dispatch(loginCompleted());
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
components
'use strict';
import React, { PropTypes } from 'react';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import ContentAdd from 'material-ui/svg-icons/content/add';
import { loginAction } from '../actions';
// import '../css/style.css';
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.loginSubmit = this.loginSubmit.bind(this);
}
loginSubmit() {
console.log('Login fomr submitted', this.props);
console.log('loginAction', loginAction);
loginAction()();
}
render () {
console.log('props when login rendered', this.props);
return (
<div className="loginForm">
<div className="title">LOGIN</div>
<form>
<TextField
hintText="Username"
floatingLabelText="Username"/><br/>
<br/>
<TextField
hintText="Password"
type="Password"
floatingLabelText="Password"/><br/>
<br/>
<RaisedButton
label="Login"
secondary={true}
onClick={this.loginSubmit}
className="submitBtn" /><br/>
<br/>
<FloatingActionButton
secondary={true}
className="registerBtn">
<ContentAdd />
</FloatingActionButton>
</form>
</div>
)
}
}
export default LoginForm;
actions/loginAction.js
'use strict';
// import { polyfill } from 'es6-promise';
// require('es6-promise').polyfill();
// require('isomorphic-fetch');
import request from 'superagent';
// import fetch from 'isomorphic-fetch';
import loginCompleted from './loginCompletedAction.js';
import loginSubmitted from './loginSubmittedAction.js';
const loginAction = (dispatch) => {
console.log('validateUserLogin executed', this);
console.log('validateUserLogin dispatch', dispatch);
return (dispatch) => {
// console.log('first return', dispatch);
// this.props.dispatch(loginSubmitted());
// this.props.dispatchAction.loginSubmitted();
dispatch(loginSubmitted());
request.get('http://localhost:3000/loginSubmit')
.end((err, res) => {
console.log('res', res);
console.log('err', err);
// this.props.dispatchAction.loginCompleted();
});
}
}
export default loginAction;
Folder structure
I am using redux-thunk
middleware that exposes dispatch function to async action creators. Still it doesn't work.
Please help!
loginAction()();
I think you need to getloginAction
from props (populated bymapDispatchToProps())
instead of importing it in your component. When you import it directly, it doesn't get wrapped, sodispatch()
is not passed into it. If it's not that line, please tell us which line causes the error! That's pretty important info. – stonedispatch(loginSubmitted());
inactions/loginAction.js
is causing the error. – Souravdispatch
, but it's expecting you to. – stonedispatch(loginAction())
, and make the change suggested by @Sag1v. Usual way to do that is inmapDispatchToProps
. Otherwisedispatch
will not be defined. You may find it helpful to study howdispatch
is passed around - it seems mysterious with all the arrow functions (well, it did to me) but there's a clear path. – stone