I'm trying to pass my isMatched variable through my action and conditionally change the boolean value based on the json response sent from the post route.
However, my current setup always returns a payload of undefined. What am I missing here within this to successfully change my values based on the data?
onSubmit = e => {
e.preventDefault();
const resetPassword = {
email: this.username,
password: this.state.password,
password2: this.state.password2,
isMatched: false
};
this.props.updateUserPassword(resetPassword);
};
// Reset Password action to dispatch isMatched to reducer
export const updateUserPassword = resetPassword => dispatch => {
axios
.post("/api/users/resetpassword", resetPassword)
.then(res => {
if (res.data.msg === 'passwords match') {
const isMatched = true;
dispatch(setMatchedPass(isMatched));
} else {
const isMatched = false;
}
})
};
// Matched Password Dispatch
export const setMatchedPass = isMatched => {
return {
type: SET_MATCH_PASS,
payload: isMatched
***** If I set this to 'testing', that's output, but if *****
***** I try to dispatch the variable isMatched, it doesn't *****
***** seem to pass the value. *****
};
};
// Matched Password Reducer
import { SET_MATCH_PASS } from "../actions/types";
const matchedState = {
isMatched: false
};
export default function (state = matchedState, action) {
switch (action.type) {
case SET_MATCH_PASS:
return {
...state,
isMatched: action.payload
};
default:
return state;
}
}
EDIT: Defining resetPassword to pass values to updateUserPassword
/* Connect Mapstate to props */
export default connect(mapStateToProps, { updateUserPassword })(ResetPassword);
onSubmit = e => {
e.preventDefault();
const resetPassword = {
email: this.username,
password: this.state.password,
password2: this.state.password2,
isMatched: false
};
this.props.updateUserPassword(resetPassword);
};
// This takes resetPassword, sets isMatched and dispatches it to setMatchedPass
export const updateUserPassword = resetPassword => dispatch => {
axios
.post("/api/users/resetpassword", resetPassword)
.then(res => {
const isMatched = true;
dispatch(setMatchedPass(isMatched));
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
//** To pass isMatched through type SET_MATCH_PASS
export const setMatchedPass = isMatched => {
console.log('setting isMatched for SET_MATCH_PASS action:', isMatched);
return {
type: SET_MATCH_PASS,
payload: isMatched
};
};
//** MatchReducer to receive the isMatched property and change the
//** state of isMatched in Store
import { SET_MATCH_PASS } from "../actions/types";
const matchedState = {
isMatched: false
};
export default function (state = matchedState, action) {
switch (action.type) {
case SET_MATCH_PASS:
return {
...state,
isMatched: action.payload
};
default:
return state;
}
}
//// **** TO RENDER THE COMPONENT **** ////
const MatchedComp = ({ isMatched }) => {
return (
<div>
{isMatched && <div>If you see this, the password is correct</div>}
</div>
);
};
MatchedComp.propTypes = {
isMatched: PropTypes.bool,
};
/// This is called in my return ///
<MatchedComp {...this.props} />
//** Mapping props / state **//
const mapStateToProps = state => {
console.log(state);
return {
auth: state.auth,
errors: state.errors,
isMatched: state.isMatched
}
};
////*** OUTPUT OF console.log(state); ***////
{auth: {…}, match: {…}, errors: {…}}
auth: {
isAuthenticated: false,
user: {…},
loading: false
}
errors: {}
match:
isMatched: true
__proto__: Object
__proto__: Object
// *** Output of {console.log('in render', isMatched)} *** ///
**in render undefined**
Dispatching an action within a reducer is an anti-pattern. Your reducer should be without side effects, simply digesting the action payload and returning a new state object. Adding listeners and dispatching actions within the reducer can lead to chained actions and other side effects.
A Redux app really only has one reducer function: the "root reducer" function that you will pass to createStore later on. That one root reducer function is responsible for handling all of the actions that are dispatched, and calculating what the entire new state result should be every time.
In your mapStateToProps
you're accessing state.isMatched
but you should use state.match.isMatched
as shown in your logged state
.
It's hard to debug without having the whole picture. But make sure that the type
you use is the same in actions and reducer.
To see how data travels and where it breaks.
// Matched Password Dispatch
export const setMatchedPass = isMatched => {
console.log('setting isMatched for SET_MATCH_PASS action: ', isMatched, SET_MATCH_PASS);
return {
type: SET_MATCH_PASS, // make sure this type is the same as in reducer
payload: isMatched
};
};
Then check in reducer you - both the action and payload:
export default function (state = matchedState, action) {
console.log('Checking again', action.type, action.payload);
switch (action.type) {
case SET_MATCH_PASS:
...
default:
return state;
}
}
EDIT (Update based on your state
console log): to show how to retrieve value from redux
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
const MyComponent = ({
isMatched
}) => {
/**
* It will re-render each time the value of `isMatched` is changed
*/
return (
<div>
{console.log('in render', isMatched) // what value do you see here?}
{isMatched && <div>If you see this, the password is correct</div>}
</div>
);
};
MyComponent.propTypes = {
isMatched: PropTypes.bool,
};
const mapStateToProps = state => {
// your value on state is stored in `match`
return {
isMatched: state.match.isMatched,
}
};
export default connect(
mapStateToProps,
null
)(MyComponent);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With