Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly dispatch variable through Redux action / reducer

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**

like image 658
Seth Spivey Avatar asked May 01 '20 14:05

Seth Spivey


People also ask

How do I dispatch action in reducer?

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.

Who is responsible for dispatching the action in Redux?

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.


2 Answers

In your mapStateToProps you're accessing state.isMatched but you should use state.match.isMatched as shown in your logged state.

like image 93
DDS Avatar answered Oct 17 '22 06:10

DDS


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);
like image 41
Uma Avatar answered Oct 17 '22 06:10

Uma