Understanding Reducer Parameters (Redux)

I have two questions about the following code that relate to the parameters of the reducer function. Here’s the code:

const defaultState = {
  login: false
};

const reducer = (state = defaultState, action) => {

if (action.type === 'LOGIN') {
  return {
    login: true
  }
  } else {
    return state
  }
};

const store = Redux.createStore(reducer);

const loginAction = () => {
  return {
    type: 'LOGIN'
  }
};
  1. I understand why state would be defaultState, but how does the program know that I want action (the parameter) to be loginAction? I don’t anywhere where it says something like reducer(state= default, loginAcction), so how does it know what I mean?
  1. In the return statements, I see login: true, but why isn’t it state.login: true/default.login: true? How does the program know that I’m refering to the defaultState action?

Thank you!

I understand why state would be defaultState , …

I would say that the default state is the state on the first call, the default. After the first time, the incoming state should be whatever was returned from the last call to the reducer.

but how does the program know that I want action (the parameter) to be loginAction ? I don’t anywhere where it says something like reducer(state= default, loginAcction) , so how does it know what I mean?

action is just a variable, in this case an action with a type. What type? Whatever was dispatched. Whatever you call with the dispatch function will get sent through every reducer. If it matches something in the logic (in this case your if/else), then the reducer will do whatever the logic says and return either the same state or a new one.

In the return statements, I see login: true , but why isn’t it state.login:

For this reducer, the state is an object. Remember that we never mutate our state objects but return new ones.

Are you asking why you can’t do:

  return {
    login: state.login
  }

Because that would not change state. I mean, it would be a new object, but the values would be the same. There are situations where you might do that or toggle it with !state.login, but in this case we want that state.login to be true.

How does the program know that I’m refering to the defaultState action?

You’re not. The only time that default parameter kicks in (like all default parameters) is if that value comes in as undefined. The only time that happens in redux is on the first call, when redux is setting up. Again, what is coming in as that first parameter after the first call, is whatever this reducer returned the last time. This all happens behind the scenes, handled by redux.

Just as a clarification, I said that the only time the default parameter gets used by redux is the first time, when it is undefined. That is true. But you sometimes still use it. Some reducers might have a 'RESET' action or something like that, in which case you might return the default state.

  1. You only have the reducer function defined, you never called it, so the program does not know what action you intend to pass to the reducer(once you call it). Only once you call the function, it will look for the action parameter and take the respective actions.
  2. The state is an object. If you look at the value assigned to the default state, its an object. The program expects the reducer function to return an object, which will represent the state. You can see what values the state can take in the code. If you pass an action with a type property equal to 'LOGIN', the state will become {login: true}. If we dont take an action, the state will be the defaultState, which is equal {login: false}

Yeah, reading over Sylvant’s post I realize that part of the problem may be that you aren’t seeing the dispatching functions that dispatch the actions created by the action creators - right now that is being done behind the scenes. It might make more sense when it gets put together. Or not - redux is weird at first and takes a while to completely wrap your head around. But it is really cook once you get it. Stick with it.

If I understand things correctly (very sketchy at this point!), the same is true for this exercise: https://www.freecodecamp.org/learn/front-end-development-libraries/redux/never-mutate-state

const ADD_TO_DO = "ADD_TO_DO";

// A list of strings representing tasks to do:
const todos = [
  "Go to the store",
  "Clean the house",
  "Cook dinner",
  "Learn to code"
];

const immutableReducer = (state = todos, action) => {
  switch (action.type) {
    case ADD_TO_DO:
      // don't mutate state here or the tests will fail

      return state.concat(action.todo);
    // or return [...state, action.todo]

    default:
      return state;
  }
};

// an example todo argument would be 'Learn React',
const addToDo = todo => {
  return {
    type: ADD_TO_DO,
    todo
  };
};

const store = Redux.createStore(immutableReducer);`

No action is shown, so it is confusing. When/how does addToDo() become action? or when is the reducer called, other than upon setup?

For that matter, const store = Redux.createStore(immutableReducer); does not appear to be an IIFE, but I guess it is run when the expression is evaluated? But…??? Sorry; read documentation, still don’t understand.

To be clear and complete, it seems the exercise should ask the student to write the action. The comment

// an example todo argument would be 'Learn React',

leaves the reader confused as to whether he is supposed to write that line of code, or not. That’s why many people have written one, and it caused their code not to pass.

To be clear and incomplete, it seems, the instructions should at least mention that addToDo is the action, and is called behind the scenes, passing a value to the reducer.

No. Just a function. Here, this is basically it, (minus error handling and the function for adding listeners):

function createStore(reducer) {
  let currentState = reducer();

  return {
    getState() {
      return currentState;
    },
    dispatch(action) {
      let currentState = reducer(currentState, action);
    }
  }
}

So

const myStore = createStore(immutable reducer);

If I run

myStore.getState();

Then it returns the value of currentState. The initial value of currentState is whatever happens if I run the reducer function with no arguments. If I run the reducer function with no arguments, I get this back:

[
  "Go to the store",
  "Clean the house",
  "Cook dinner",
  "Learn to code"
];

So that’s what I get when I run myStore.getState().

If I run

myStore.dispatch(addTodo("do some work"))

addTodo is a function that returns { type: "ADD_TODO", todo: "do some work" }. So

myStore.dispatch({ type: "ADD_TODO", todo: "do some work" })

dispatch sets the value of the state to whatever the reducer function returns. Running the reducer function with the current state + the action is

immutableReducer([
  "Go to the store",
  "Clean the house",
  "Cook dinner",
  "Learn to code"
], { type: "ADD_TODO", todo: "do some work" })

That returns a copy of the state with the value of the action’s todo field added on the end. That’s set to the current state. Then if I run myStore.getState(), it returns

[
  "Go to the store",
  "Clean the house",
  "Cook dinner",
  "Learn to code"
  "do some work"
]

And so on and so forth

Thank you for a clear and concise explanation of how these Redux parts function together. You answered part of my question. It sounds like I did understand that much correctly.

The questions remain, however, since
‘function createStore(…)’
is a function definition, and since
‘const immutableReducer = (…)’, and ‘constAddToDo = (…)’
are also “regular” function expressions, not IIFEs, they have to be called by something, so

  1. When is createStore() FIRST run?
    and
  2. When is dispatch() actually run?

Aren’t these Javascript questions, and lesson presentation questions, not Redux questions?

You said,
" If I run

myStore.dispatch(addTodo("do some work"))

and
"If I run

myStore.getState();

I get how this works, but, those are “Ifs.” Unless I’m missing something, nowhere in this exercise does either function CALL actually appear, nor does the lesson say that the functions are CALLED behind the scenes, and if the user puts it in a dispatch() function CALL, he does not pass the lesson.

Does it not seem to you that it is a confusing lesson to which the correct answer is defining functions that are never called, and to which calling the functions yields code that will not pass? Or am I confused about when functions are called? Or is it both/and?

Apologies for a pithy answer, but

When is createStore() FIRST run?

Whenever you want

When is dispatch() actually run?

Whenever you want, as long as you’ve run createStore first, given that dispatch is part of the return value of createStore

As with all other challenges in FCC, the test runs the function. It isn’t defined because all the test does is run the function you define with some test parameters.

It just takes the chunk of code you’ve written, runs createStore with that chunk, then checks that works fine

Sorry, but the pithy answers were not all that helpful. I guess you mean that I was correct about these functions needing to be called, but I think you are confusing my question about code in the editor with a question about code in the testing.

You said,

As with all other challenges in FCC, the test runs the function. It isn’t defined because all the test does is run the function you define with some test parameters.

Huh? I wouldn’t expect the curriculum’s testing code to “be defined” visibly in the editor where the student is writing code.

It just takes the chunk of code you’ve written, runs createStore with that chunk, then checks that works fine

Of course it does.

Perhaps for not looking at the context, you missed the point, which, after clarifying the mechanics of javascript and Redux, still stands. My post was written in response to @kevinSmith , who observed, in reply to @Sylvant :

“Yeah, reading over Sylvant’s post I realize that part of the problem may be that you aren’t seeing the dispatching functions that dispatch the actions created by the action creators - right now that is being done behind the scenes.”

In every exercise to this point, the student was asked to INVOKE a function, thereby involving, somewhere in the process, the rest of the code the student had written, or had been given, i.e., the code in the editor. The results are then usually visible in the third pane.

The testing also ran functions, usually passing in a variety of values, to check whether your code ran according to the lesson instructions/requirements.

Never Mutate State is the first lesson, to my recollection, to ask the student to write functions that WERE NOT ACTUALLY INVOKED BY CODE VISIBLE IN THE EDITOR. The lesson referenced in the original post on this thread is like to it, in that respect. This is what confused the OP, and this is why I posted on this thread, because the two lessons had the same problem; I just added another example, to reinforce @kevinSmith 's point.

One of three things should be done to improve the lesson:

  1. The lesson should provide a visible dispatch function in the editor, or
  2. The student should be asked to provide the dispatch function in the editor, and the testing should be modified to allow for it, or,
  3. The student should be informed that he does not need a dispatching function in the editor, that it will be run behind the scenes by the testing.

The thing is, what do you teach first? You need to understand that these are just very basic functions and you absolutely need to understand it has to be pure. But if you start with the useStore function, that hides what the reducer (the actual thing you need to write) does, it’ll just be a magic “send an object into this function and out pops this state from nowhere”. And yes, if you start with the reducer, then that elides what the useStore function. But this is a chicken and egg situation, it needs to be in bit-size chunks the same as the rest of the curriculum, not “here is absolutely everything”. Getting you to write a reducer first before explaining the useStore is fine, because it’s a small chunk, you get the next part next and the next after that and so on.

Redux itself is trivially simple, but it makes quite complicated code that will make no sense unless you put the individual bits together.

Edit: ok I assumed this came much earlier on. I can understand why you and the OP were confused, the wording could be altered very slightly to make it more obvious, but it definitely does not ask you to do that.

If you run dispatch on the store with the reducer function the challenge is about, that should work. But the function the challenge is asking you to fill in is not that: it’s the reducer, which you can run exactly as is asked in tests, and you could, if you wished, put a log there and leave it there you want, that would not cause the test to fail because the function is, as the test is checking, pure

Ah, I see your edit. I think the console log suggestion sounds good. I am still surprised how often people suggest that in places I or other newbies didn’t think to use it.

After I looked at all the lessons, I realized the problem did come up fairly early. Since my reply to your last response, pre-edit, is still relevant, I’ll go ahead and post it:

createStore() was explained in the first lesson.

Sure, in the first few lessons, tiny parts, one at a time works fine, but the OP appears to be on lesson 6, “Handle an Action in the Store” and has just been introduced to how to store, state, action, action creator, and, in lesson 5, "Dispatch an Action Event, so he knows that needs to happen for his code to function.

From this point on, all the essential parts of a redux app should be included, so the student can learn by seeing the pattern of how the program works; the flow; It starts with a dispatched action.

I wrote,

In every exercise to this point, the student was asked to INVOKE a function, …

but that was not actually the case. Some of the lessons include all the basic parts of a Redux app, and ask the user to supply the missing part. That is a very effective way to teach the material. As things are, several other lessons are lacking all the parts, which I think causes unnecessary confusion, and they could be improved by one or more of the three methods I suggested.

By the time you get to lesson 13, Write a Counter with Redux, which also omits the dispatch(), you’ve spent 12 lessons learning the parts, and the instructions, (https://www.freecodecamp.org/learn/front-end-development-libraries/redux/write-a-counter-with-redux), say:

Now you’ve learned all the core principles of Redux! You’ve seen how to create actions and action creators, create a Redux store, dispatch your actions against the store, and design state updates with pure reducers. You’ve even seen how to manage complex state with reducer composition and handle asynchronous actions. These examples are simplistic, but these concepts are the core principles of Redux. If you understand them well, you’re ready to start building your own Redux app. The next challenges cover some of the details regarding state immutability, but first, here’s a review of everything you’ve learned so far.


… and then it omits the dispatch()?

It’s a question of when to transition from part-to-part, to part-to-whole, and whole-to-part learning modes. I say: get to whole-to-part as soon as possible.

Well, that was a long and challenging conversation (I was up at 4am…early for me), and that may be only 10% of the work. If my learning theory is valid, changing the lessons and/or the testing might be the other 90% of the work. I will not do a pull request right now, because I want to get through the curriculum.

But I swear, at least one fcc curriculum pull request is on the agenda as part of my portfolio :sweat_smile:

If theory is not valid, or worth implementing, then at least I learned Redux better by laboring to explain.

Thanks for responding! I do appreciate those who help on this forum, and all the work put into freeCodeCamp! :grinning: