I'm trying to dispatch an action when the user submits a form. Let's say I have a submit button that triggers an onSubmit
event on the form (and eventually will show a spinner icon while the form request is being processed but at this point, the submit button just shows a true
or false
value representing whether or not the spinner is being shown).
LoginPage.js
import React from 'react';
import { Link } from 'react-router-dom';
export class LoginPage extends React.Component {
constructor(props) {
super(props);
this.handleLogin = this.handleLogin.bind(this);
}
handleLogin(e) {
e.preventDefault();
let email = document.getElementById('userEmail').value;
let password = document.getElementById('userPassword').value;
this.props.loginHandler(email, password);
}
render() {
return (
<form onSubmit={ this.handleLogin }>
<input type="submit" value={ this.props.requestingLogin } />
</form>
);
}
}
export default LoginPage;
LoginPageContainer.js
import React from 'react';
import { connect } from 'react-redux';
import LoginPage from '../../ponents/login/LoginPage';
import { loginUser } from '../../actions';
export class LoginPageContainer extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<LoginPage requestingLogin={ this.props.requestingLogin } loginHandler={ this.props.loginUser } />
);
}
}
const mapStateToProps = state => {
const { loginUserReducer } = state;
return {
requestingLogin: loginUserReducer.isRequestingLogin,
};
};
const mapDispatchToProps = dispatch => {
return {
loginUser: (email, password) => {
dispatch(loginUser(email, password));
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginPageContainer);
index.js in actions/
export const REQUEST_LOGIN = 'REQUEST_LOGIN';
function requestLogin() {
return {
type: REQUEST_LOGIN,
};
};
export const loginUser = (email, password) => {
return dispatch => {
// this works because when the button is clicked,
// I can successfully console log in here.
dispatch(requestLogin); // THIS DISPATCH IS NOT WORKING
// API call here...
}
};
index.js in reducers/
import { bineReducers } from 'redux';
import { REQUEST_LOGIN } from '../actions';
const initialLoginState = {
isRequestingLogin: false,
};
function loginUserReducer(state = initialLoginState, action) {
switch(action.type) {
case REQUEST_LOGIN:
return Object.assign({}, state, { isRequestingLogin: true });
default:
console.log('returned from default');
return state;
}
}
const allReducers = bineReducers({
loginUserReducer,
});
export default allReducers;
What's weird is that my API call that I have after the dispatch()
inside loginUser()
works but the dispatch()
doesn't work.
I've seen many tutorials online and my code matches what I've seen but for some reason I can't figure out why dispatch the action is not working. Any help would be greatly appreciated.
I'm trying to dispatch an action when the user submits a form. Let's say I have a submit button that triggers an onSubmit
event on the form (and eventually will show a spinner icon while the form request is being processed but at this point, the submit button just shows a true
or false
value representing whether or not the spinner is being shown).
LoginPage.js
import React from 'react';
import { Link } from 'react-router-dom';
export class LoginPage extends React.Component {
constructor(props) {
super(props);
this.handleLogin = this.handleLogin.bind(this);
}
handleLogin(e) {
e.preventDefault();
let email = document.getElementById('userEmail').value;
let password = document.getElementById('userPassword').value;
this.props.loginHandler(email, password);
}
render() {
return (
<form onSubmit={ this.handleLogin }>
<input type="submit" value={ this.props.requestingLogin } />
</form>
);
}
}
export default LoginPage;
LoginPageContainer.js
import React from 'react';
import { connect } from 'react-redux';
import LoginPage from '../../ponents/login/LoginPage';
import { loginUser } from '../../actions';
export class LoginPageContainer extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<LoginPage requestingLogin={ this.props.requestingLogin } loginHandler={ this.props.loginUser } />
);
}
}
const mapStateToProps = state => {
const { loginUserReducer } = state;
return {
requestingLogin: loginUserReducer.isRequestingLogin,
};
};
const mapDispatchToProps = dispatch => {
return {
loginUser: (email, password) => {
dispatch(loginUser(email, password));
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginPageContainer);
index.js in actions/
export const REQUEST_LOGIN = 'REQUEST_LOGIN';
function requestLogin() {
return {
type: REQUEST_LOGIN,
};
};
export const loginUser = (email, password) => {
return dispatch => {
// this works because when the button is clicked,
// I can successfully console log in here.
dispatch(requestLogin); // THIS DISPATCH IS NOT WORKING
// API call here...
}
};
index.js in reducers/
import { bineReducers } from 'redux';
import { REQUEST_LOGIN } from '../actions';
const initialLoginState = {
isRequestingLogin: false,
};
function loginUserReducer(state = initialLoginState, action) {
switch(action.type) {
case REQUEST_LOGIN:
return Object.assign({}, state, { isRequestingLogin: true });
default:
console.log('returned from default');
return state;
}
}
const allReducers = bineReducers({
loginUserReducer,
});
export default allReducers;
What's weird is that my API call that I have after the dispatch()
inside loginUser()
works but the dispatch()
doesn't work.
I've seen many tutorials online and my code matches what I've seen but for some reason I can't figure out why dispatch the action is not working. Any help would be greatly appreciated.
Share Improve this question edited Nov 30, 2017 at 3:03 Ol' Reliable asked Nov 30, 2017 at 2:09 Ol' ReliableOl' Reliable 5701 gold badge8 silver badges19 bronze badges 6-
does your page reloads after you click on
submit
? – Panther Commented Nov 30, 2017 at 2:38 -
No, I have
e.preventDefault();
in thehandleLogin()
method which I forgot to put with the question – Ol' Reliable Commented Nov 30, 2017 at 3:02 -
5
all you have to do is change
dispatch(requestLogin);
todispatch(requestLogin());
and may be pass the required data to action. – Panther Commented Nov 30, 2017 at 3:34 - @Panther this made it work! Thanks a lot! Can you please create an answer? – Ol' Reliable Commented Nov 30, 2017 at 3:48
- @Ol' Reliable got the same issue. any suggestion for solution?? – Vikas Gupta Commented Jan 18, 2019 at 11:22
2 Answers
Reset to default 8The problem is here:
const mapDispatchToProps = dispatch => {
return {
loginUser: (email, password) => {
dispatch(loginUser(email, password)); [DISPATCH ACTION]
}
}
};
So loginUser is a function that take email, password and call dispatch(loginUser(email, password))
But loginUser(email, password) doesn't return an action, instead, it returns a function.
export const loginUser = (email, password) => {
return dispatch => {
// this works because when the button is clicked,
// I can successfully console log in here.
dispatch(requestLogin); // THIS DISPATCH IS NOT WORKING
// API call here...
}
};
So the line [DISPATCH ACTION]
doesn't dispatch an action but dispatch a function instead.
To make it correct, you can change like following:
const mapDispatchToProps = dispatch => {
return {
loginUser: (email, password) => {
loginUser(email, password)(dispatch);
}
}
};
So, loginUser returns a function, you call it with dispatch as a parameter. But it doesn't seem to be pretty. How to do it correctly?
export const loginUser = dispatch => {
return (email, password) => {
// this works because when the button is clicked,
// I can successfully console log in here.
dispatch(requestLogin()); // THIS DISPATCH IS NOT WORKING
// API call here...
}
};
And in mapDispatchToProps:
const mapDispatchToProps = dispatch => {
return {
loginUser: loginUser(dispatch)
}
};
You should definitely try using e.stopPropagation(). If other stuff inside the function works while dispatch not, then you can try this. It worked for me.