Linking action to store (redux)

i understand how a dispatch method would send a message to a store (and hence onto the reducer), but in this code I see no connection between the action and the other parts of code. Do I assume the dispatch method is working behind the scenes, or else I’m feeling a touch confused.

  **Your code so far**
const ADD = 'ADD'; 
const addMessage = message => {
return {
  type: ADD,
  message
};
}

const messageReducer=(previousState=[], action) => {
switch(action.type){
  case ADD:
    return [...previousState, action.message];
  default:
    return previousState;
}
}

const store = Redux.createStore(messageReducer)

  **Your browser information:**

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36

Challenge: Extract State Logic to Redux

Link to the challenge:

function createStore (reducer) {
  let state;

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

:point_up_2: that’s Redux.

If you follow the logic there and substitute in what you’ve written, can you see what’s happening a bit more clearly?

you’re saying that’s happening in the const store = Redux.createStore(messageReducer) place?
if so i still don’t see where it connects addMessage.

I feel like I’m missing something in redux but it might be best to struggle through and see where I am in a revision.

So addMessage is just a helper that you’ve written (it is IMO more confusing having that helper that just writing out a plain object but anyway)

addMessage("hello")

Is exactly the same as

{ type: "ADD", message: "hello" }

Then what I posted, that’s literally what Redux is. It’s the only bit of code you haven’t written.

Do what I’ve said here, substitute the values in: these are very simple functions. So createStore returns an object with two functions attached.

If you run store.getState(), what’s the value?
If you then run store.dispatch({ type: "ADD", message: "hello" }), what is the value you get from store.getState() now?


there is one other function in the actual version, addListener that gets returned with getState & dispatch, + some error handling, but that’s all

thanks. i am busy and will try that later, but that makes sense already.

1 Like

So the addMessage action is passed into the dispatch method which then acts upon the store.
There’s the link. Got that, thanks.
(not sure what you meant by ‘substitute the values in’, but my question is answered)

const ADD = 'ADD'; 
const addMessage = message => {
  return {
    type: ADD,
    message
  };
}

const messageReducer=(previousState=[], action) => {
  switch(action.type){
    case ADD:
      return [...previousState, action.message];
    default:
      return previousState;
  }
}

const store = Redux.createStore(messageReducer)

And

function createStore (reducer) {
  let state;

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

You know what the function addMessage does, so substitute it when you use it for its actual value. Can also subsitute of the ADD for “ADD”, inlining that as well, and replace Redux.createStore with the actual implementation.

// This will be the message:
// { type: "ADD", message: "hello" }

function messageReducer (previousState = [], action) {
  switch(action.type){
    case "ADD":
      return [...previousState, action.message];
    default:
      return previousState;
  }
}

function createStore (reducer) {
  let state;

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

const store = createStore(messageReducer);

The value of store is now an object with two functions attached to it, called getState and dispatch.

So I run

store.getState()

If I look at the definition of createStore, what getState does is just return the value of the variable state in the createStore function (this is a closure).

The value of that is undefined -

function createStore (reducer) {
  let state;

So store.getState() returns undefined

So I then run

store.dispatch({ type: "ADD", message: "hello" })

Again looking at the definition of createStore, what dispatch does is set state to the return value of running your reducer with the current value of state and the argument given to dispatch.

messageReducer(undefined, { type: "ADD", message: "hello" })

In your messageReducer function, if the value given as previousState is undefined, it defaults to an empty array, so it’s actually running

messageReducer([], { type: "ADD", message: "hello" })

Now you can check what happens in the switch statement: for the type of "ADD", you return a new array based on the current one, with the value of message concatenated onto any current values. There aren’t any existing values, it’s an empty array. Return value is:

["hello"]

So back to createStore's dispatch function. That sets state to ["hello"].

So then run store.getState() again. This time the value of state is not undefined. It’s

["hello"]

Dispatch again:

store.dispatch({type: "ADD", message: "hello again" })

Reducer runs, this time there’s a value to pass to previousState. The type is "ADD", the message is "hello again", return value is

["hello", "hello again"]

If run getState, that will be the result. And so on and so forth.


Technically it doesn’t really get much more complicated than that (with caveats, mainly related to doing asynchronous things, but the way asynchronous events are handled in redux is the same, but with an extra step).

It is basically the same as JS browser events: click, touch, drag etc. So like, in React you have

<button onClick={/* some function to run */}>

In plain JS,

myButton.addEventListener("click", /* some function to run */)

The event type is “click”

Actions in Redux are events (the name “action” is wrong, but the name “event” was already taken). You have a type of event, you check what the event is, you do something. And the something you do is return a new state for the app. It’s just done very explicitly, the machinery is fully exposed rather than hidden in the functionality provided by the browser.

In practice you want events for every possible action that you want to affect the state. So even in a small app you end up with lots of actions and state and complicated reducer logic to remake the state. These examples here are very very small, and seem almost pointless. But it’s impossible to explain how to use it by starting with complex examples.


the state variable in createStore could be initialised like this, instead of being undefined:

let state = reducer(undefined, undefined);

Because the first argument (previousState defaults to [], and the second causes the switch to hit the default and just return previousState, that would set the initial state to [].

What Redux’ actual createStore does is run dispatch once before returning. Because the dispatch returns the action, if development tools have been set up for Redux, a developer can then see in a console when the store has fully initialised.

There is also another function that createStore returns, called addListener, that I didn’t include. It’s also very simple. It takes a function as an argument. When addListener is ran it adds that function to an array stored alongside state in the store. Whenever `dispatch runs, it runs every function in the array before returning. This is how you get React to update whenever something is dispatched to update the state.

1 Like

thank you. thats much much clearer. I’m gonna have a play with that code before getting back to the regular Redux.
I will mention, I seem to have succeded in setting initial state simply by declaring

function createStore (reducer) {

  let state=[];

…but I see how

let state = reducer(undefined, undefined);

…works and will assume it’s more robust and move on.
thanks again.