FAQ: Intro to the Core Redux API - Respond to State Changes

This community-built FAQ covers the “Respond to State Changes” exercise from the lesson “Intro to the Core Redux API”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Learn Redux

FAQs on the exercise Respond to State Changes

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!
You can also find further discussion and get answers to your questions over in Language Help.

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head to Language Help and Tips and Resources. If you are wanting feedback or inspiration for a project, check out Projects.

Looking for motivation to keep learning? Join our wider discussions in Community

Learn more about how to use this guide.

Found a bug? Report it online, or post in Bug Reporting

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

import { createStore } from 'redux';

const increment = () => {
  return { type: 'increment' };
}

const decrement = () => {
  return { type: 'decrement' };
}

const initialState = 0;
const countReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'increment':
      return state + 1;

    case 'decrement':
      return state - 1;

    default:
      return state;
  }
}

const store = createStore(countReducer);

// Define your change listener function here.
const printCountStatus = () => {
  console.log(`The count is ${store.getState()}`);
}

store.subscribe(printCountStatus);

store.dispatch(decrement()); // store.getState() === -1

store.unsubscribe(printCountStatus);  // <-- Why cant?

store.dispatch(increment()); // store.getState() === 0
store.dispatch(increment()); // store.getState() === 1

Why I can’t just add store.unsubscribe(printCountStatus); like this? Can someone explain?

1 Like

Feel free to correct me if anything is off here, but from my understanding of the redux docs here, it seems that store (instantiated from the createStore function) does not have an unsubscribe method store.unsubscribe(listener) to call.

Instead, it is returned from the subscribe function defined in createStore as shown below in an example breaking down the createStore function :

function createStore(reducer, preloadedState) {
  let state = preloadedState
  const listeners = []

  function getState() {
    return state
  }

  function subscribe(listener) {
    listeners.push(listener)
    return function unsubscribe() {
      const index = listeners.indexOf(listener)
      listeners.splice(index, 1)
    }
  }

  function dispatch(action) {
    state = reducer(state, action)
    listeners.forEach(listener => listener())
  }

  dispatch({ type: '@@redux/INIT' })

  return { dispatch, subscribe, getState }
}

So, when we assign our named function expression (unsubscribe) as the return value of createStore(reducer), we then can then access it later through unsubscribe() .

However, I’m confused as to why

store.subscribe(listener)

and

const unsubscribe = store.subscribe(() => console.log('State after dispatch: ', store.getState()) )
both seem to instantiate the subscription to the store. I thought that in the latter case, we are simply creating a named function expression named ‘unsubscribe’ and not directly calling store.subscribe().

Could someone explain this?

This exercise is a total dilemma to me.

An example code is provided that gives us this:

// lightSwitchReducer(), toggle(), and store omitted...
 
const reactToChange = () => {
  console.log(`The light was switched ${store.getState()}!`);
}
const unsubscribe = store.subscribe(reactToChange);
 
store.dispatch(toggle());
// reactToChange() is called, printing:
// 'The light was switched off!'
 
store.dispatch(toggle());
// reactToChange() is called, printing:
// 'The light was switched on!'
 
unsubscribe(); 
// reactToChange() is now unsubscribed
 
store.dispatch(toggle());
// no print statement!
 
console.log(store.getState()); // Prints 'off

These are the parts that I don’t understand:

  • Isn’t this the way to subscribe a change listener to the store?
    store.subscribe(reactToChange);
    Then why are we using it as an unsubscribe function?

  • Why is it that when we declare this line of code…
    store.dispatch(toggle());
    reactToChange() is being called?

I’d really appreciate it if someone clears these things.

1 Like

Okay this one I think I can answer -

By setting store.subscribe(reactToChange) we are saying ‘whenever a change/event is detected perform an action’ - subscribe() is a method that listens for events and in this case the function reactToChange() is the action being performed. When you declare store.dispatch(toggle() you are changing something - the state is being toggled. When that happens subscribe() detects it and calls reactToChange().

As for your first question, I’m not sure. Unless subscribe() method itself toggles between being on and off, so every time you call it just swaps. In that case declaring unsubscribe() might just be to avoid confusion??

PS. This is my first time trying to answer a question in the forum instead of just asking them - if anyone spots any errors please let me know.

1 Like

The implementation of unsubcribe isn’t intuitive but, as you’d expect, it’s obvious when you know! So here goes: -

This code sets-up aFunction() to be called whenever a change to the state happens ie. aFunction() becomes a ‘subscribed listener’ →

store.subscribe(aFunction);

This next code does exactly the same but, in addition, creates a variable called myUnsubscribe, which is a function that can be called to undo that subscription →

const myUnsubscribe = store.subscribe(aFunction);

That happens because when you call store.subscribe() it returns unsubscribe functionality, which can be captured into a variable, in this example I’ve used myUnsubscribe but you can call it any valid function name.
Given the ambiguity, how about →

const itsNotObviousWhyImAnUnsubscribeFunction = store.subscribe(iWillBeCalledWheneverAnActionIsDispatched);

Hi Paulra,

Thank you for your explanation. Can you please explain why entering the function twice does not undo the subscription?

E.g. instead of

const unsubscribe = store. subscribe(aFunction);
unsubscribe();

We do this instead:

store.subscribe(aFunction);
store.subscribe(aFunction);

Why does the above not undo the function?

Hi jpat534!

store.subscribe(aFunction);

is all you need to subscribe

however!

when the developers of the language were deciding on how they would offer us the way to unsubscribe, they settled on returning a function from the call to subscribe. This means that whenever you call →

store.subscribe(aFunction);

it returns a function that you will use to unsubscribe the listener. To gain access to that function, you can put it into a constant like this →

const myUnsubscribe = store.subscribe(aFunction);

then, when you need to unsubscribe, call it like you would any function →

myUnsubscribe();

NB: I have used the name ‘myUnsubscribe’ here but you can use any name. If you called your constant ‘releaseSubscription’ you’d declare it like this →

const releaseSubscription = store.subscribe(aFunction);

then when you wanted to unsubscribe, you’d call it like this →

releaseSubscription();

I hope that helps!
Paul.

1 Like

Thank you! That was very helpful :slight_smile:

1 Like