Write a Counter with Redux

Tell us what’s happening:

Your code so far


const INCREMENT = 'INCREMENT'; // define a constant for increment action types
const DECREMENT = 'DECREMENT'; // define a constant for decrement action types

const counterReducer = (state = 0, action) => {
  switch(action.type){
  case INCREMENT: 
    return state + 1;
  break;

  case DECREMENT : 
    return state -1;
  break;

  default: 
 return state;

  }
  
}; // define the counter reducer which will increment or decrement the state based on the action it receives

const incAction = () => {
  return {
    type : INCREMENT
  }
}; // define an action creator for incrementing

const decAction = () => {
  
  return {
    type: DECREMENT
  }
  
}; // define an action creator for decrementing

const store = Redux.createStore(counterReducer); // define the Redux store here, passing in your reducers

Your browser information:

User Agent is: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/front-end-libraries/redux/write-a-counter-with-redux

5 Likes

Passes for me, did you have a question?

1 Like

Hi there,
in place of:
case INCREMENT:
return state + 1;
break;

I wrote:
return state++;
and it won’t work. Would anyone care to explain why?

One of the rules of Redux is “Do not mutate state.” You are not supposed to change it.

return state + 1; does not mutate state. It creates a new number by taking the old state and adding 1 to it.

return state++; is actually changing state. It is going to that memory location and changing the variable adding 1 to it, altering the original.

Never mutate state. Period. Every time we mutate state, a puppy dies. Or more accurately, Redux cannot work properly.

12 Likes

Sir, when an action is dispatched to the store won’t it is going to call counterReducer with parameter state = 0
again and not with previous value of state? Sir I don’t know how counterReducer function works behind the scenes

when an action is dispatched to the store won’t it is going to call counterReducer with parameter state = 0 again and not with previous value of state?

No. You are not understanding the ES6 feature of default parameters.

Yes, normally if you do state = 0, you are assigning the value of 0 to the variable state. But, if it is inside the parameters of a function, it will only happen if the value is undefined. So, after the first time, state is not undefined so it will not get 0 assigned to it.

Let us know if this still isn’t clear.

Sir, I understand the concept of default parameters, if I don’t explicitly give arguments to the function, It will call state = 0(default value). But what I do not understand, How is it going to increment or decrement the same (state) value? for. for eg. If I am giving INCREMENT action 2 time will the state be 2 or 1 and why?

Because inside your reducer you have:

switch(action.type){
  case INCREMENT: 
    return state + 1;

  case DECREMENT : 
    return state -1;

  default: 
    return state;
}

When you return state + 1, that becomes the new state for that property of the store. That’s how you tell a reducer what the new state should be, you return the new value.

If you call it with ADD, it is going to return the old state plus 1 and that becomes the new state (on that property of the store, in this case, probably store.counter.

Is that clear? Yes, it is an odd way to think, but once you wrap your head around it, it makes sense.

1 Like

Now I get it sir , thank you for having patience with me and my stupid questions because I am very new to programming

3 Likes

There’s nothing “stupid” about it. It confused the heck out of me when I was learning it, too. Never stop asking questions. The people I pity are the people too embarrassed or proud to ask.

4 Likes

Just a little syntax improvement: You can do this:

const decAction = () =>({
    type:DECREMENT
})

shorter/cleaner :wink:

Whether or not that is an improvement is debatable. I’d agree that it’s about 75% right. But I often do the return statement in the beginning for debugging purposes and then convert them over afterwards. Of course, it all compiles into the same thing, so all you’re saving yourself is a few lines of text.

1 Like

Use if, else instead of switch.

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

const counterReducer = (state = 0, action) => {
    if (action.type === INCREMENT) {
        return (state += 1);
    } else if (action.type === DECREMENT) {
        return (state -= 1);
    }
    return state;
}

const incAction = () => {
    return {type: INCREMENT};
}

const decAction = () => {
    return {type: DECREMENT};
}

const store = Redux.createStore(counterReducer);

you can do: return ++state; it will work because the operator first it will increment and then it returns the state.

But this would be a violation of the rule to never mutate state. Every time you mutate state, Dan Abramov comes to your house and kills a puppy. You should always create a completely new version of state (without changing the old one) and return that new version of state. Returning ++state would alter state, and returning state + 1 would not.

1 Like

Would It be possible to increment the state in the action creator functions ? like this :

const INCREMENT = 'INCREMENT'; // define a constant for increment action types
const DECREMENT = 'DECREMENT'; // define a constant for decrement action types

const initialState = 0;

function counterReducer(initialState, action ) {
  switch(action.type){
    case INCREMENT: 
      return state;
    case DECREMENT: 
      return state;
    default:
      return state
  }
}; // define the counter reducer which will increment or decrement the state based on the action it receives

function incAction() {
  return {
    type: INCREMENT,
    state: initialState + 1
  }
}; // define an action creator for incrementing

function decAction() {
  return {
    type: DECREMENT,
    state: initialState - 1
  }
}; // define an action creator for decrementing

const store = Redux.createStore(counterReducer, initialState);


First of all, welcome to the forum.

That wouldn’t work. First of all, you shouldn’t pass state in on the action object. The state is pre-existing and passed in separately - and the action object is saying what you want to do to state, or the information that the reducer needs - but the change happens in the reducer. That pretend state that you are passing in would be referenced in the reducer as action.state. But don’t do this. This is not how redux works.

The other problem is that you are trying to use the initialState in your action. First of all, in the real world, reducers and action creators are often in different files so this would not work. The other problem is that your initialState is always 0 so adding one to that will always give 1, no matter how many times you press it.

In theory, if your action creator had access to the state (perhaps passed into the component) and added 1 to it and passed that, and references it on the action object correctly, then that could work. But I wouldn’t call it state because that would be too confusing.

I know redux is confusing. But if you drink the coolaid and just do what it tells you to, it is incredibly powerful. Just keep using it the right way and it will start to make sense.

1 Like

I agree with @kevinSmith

Perhaps consider this.setState to create a new state of “state +1”.

That would depend whether he’s trying to do it in the app store created by redux or in the local state of the component.

Sometimes you have both. The app we have at work uses redux for the app state. But when I built a show/hide button for the password in the login component, I just used the local state of the component because the app doesn’t need to know about whether or not the password is hidden. Most everything in the app is in the redux store, but there are a few small things like this that only one component needs to know about.

But he is working with redux here so he should not be using this.setState to change the redux state. Those are two completely different things. You can use one, or you can use the other, or you can use both if you keep them separately.

OK, many thanks for taking the time to reply,

I’ll take the time to understand it :wink: