Julian
Julian

Reputation: 9140

Prevent reducer property from nesting in state

I want my component to have a boolean property called waiting. I trigger changes on this property via the setWaiting action creator. The only problem is that inside my component this property arrives nested inside a property of the same name:

In my component I want to be able to do:

{this.props.waiting}

... but right now what I have to is:

{this.props.waiting.waiting}

Action creator:

export const WAITING = "waiting";

export function setWaiting(isWaiting) {
  return {
    type: WAITING,
    payload: isWaiting
  };
}

In my component I call this action like this:

this.props.setWaiting(true); // or false depending the case

Reducers setup:

import { combineReducers } from "redux";
import { reducer as formReducer } from "redux-form";
import waitingReducer from "./reducer-waiting"

const rootReducer = combineReducers({
    form: formReducer,
    waiting: waitingReducer
});

export default rootReducer;

Reducer:

import _ from "lodash";
import { WAITING } from "../actions";

export default function waitinReducer(state = {}, action) {
  if (_.isUndefined(state.waiting)) {
    return Object.assign({}, state, { waiting: false });
  }

  switch (action.type) {
    case WAITING:
      // This is irrelevant here because the problem happens before this
      // ever gets called. Just left it here for completeness sake.
      return Object.assign({}, state, { waiting: action.payload });
    default:
      return state;
  }
}

Map state to props (which already comes with a "bad" state):

let mapStateToProps = state => {
  // This prints { waiting: { waiting: false } }
  // but I just want { waiting: false }
  console.log(state) 

  return {
    waiting: state.waiting
  }
}

Some extra context:

react: 16.4.1
react-dom: 16.4.1
redux: 3.7.2
react-redux: 4.4.9

Upvotes: 0

Views: 59

Answers (2)

Kamalakannan J
Kamalakannan J

Reputation: 2998

Basically the change you want should happen in the reducer. You're using a object as state and setting waiting property inside the object. If you want only that boolean value, use that boolean as the state object, like below.

export default function waitinReducer(state = false, action) {
  // default initialisation is false
  // if (_.isUndefined(state.waiting)) {
  //  return Object.assign({}, state, { waiting: false });
  // }

  switch (action.type) {
    case WAITING:
      // just return the payload
      return action.payload;
    default:
      return state;
  }
}

Try this and let me know whether this works for you. One concern I have is, it won't update the props, since it's boolean is primitive type and value is stored not the reference.

Easiest change is @SamVK answer

Upvotes: 1

SamVK
SamVK

Reputation: 3435

You could try mapping just that state:

let mapStateToProps = state => ({
    waiting: state.waiting.waiting
})

That'll keep each reducer as an object but at least not give you that awkward repetitiveness in the props themselves.

Upvotes: 1

Related Questions