• selinov

Learning Redux on Ye Olde Click Demo

Live Demo

Github Repo


A wise person once told me, "Never install a dependency that you don't understand onto the app you're currently developing."


I've taken that advice to heart. ❤️ In preparation for a full Redux refactor on the Slektor app I've torn into an old click demo from my boot camp. It took a while to wrap my head around exactly how Redux works and why it's handy on larger projects. Needless to say, I'm a convert!



This is not a tutorial so I won't get into the step-by-step of how to install and use Redux. This post is about communicating an understanding of how I refactored a simple React app in order to learn.


The original click-demo used local state hooks… which I love maybe a little too much… to manage a simple variable called "counter". Counter holds a number. Nothing else. Just a simple integer. I used setState() to either +1 or -1 depending on the button pushed. Like I said, simple click demo.


Redux would be keeping state in a "container" so there's no more need for my useState() & setState() methods. Instead I'd be "dispatching" commands to Redux to change the state for me. Well, technically I think it's continuously replacing the state because with Redux state is immutable.


After installing the dependency it was time to initialize a "store", an object that Redux uses to store the current state of the app. There's a file at /store/configureStore.js which holds the base store creation block.


import { createStore } from "redux"

export default () => {
  const store = createStore(rootReducer)
  return store
}

We call this function on the app index.js file and wrap the entire <App /> call in a "provider". This provider simply supplies a tag pass the store into. The index now contains the following code.


import configureStore from "./store/configureStore"

const store = configureStore()

ReactDOM.render(
 <Provider store={store}>
 <App />
 </Provider>,
 document.getElementById("root")

We've created a store and passed that store over to the app. Then it was time to start giving Redux some commands. How you ask? That was the confusing part for me.


The Redux chain to modify the state uses an architecture of…




Action : A function that tells the reducer what type of command I'm sending.

Reducer : A simpler function that updates the store.

Store : The object holding the state.


What threw me for a loop was the purpose of having both the Action and the Reducer. It seemed like they did the same thing. It was later, as I attached all this to Firebase, that I realized that the actions need to stay decoupled from the reducer. The reducer sends the final command to update the store(state). The action can have all kinds of database calls, DOM modifications, and other tom foolery. The action is where… uh… the action is!


In order to keep the function that mods the state pure I've been told to not mess with it too much. We do that by messing with the actions instead. That way things break less. Understanding this concept is at the core of understanding Redux, IMO.


Now there's a directory for actions, reducers, and store respectively. There's a nice separation of concerns that scales with app complexity. All that's left is to connect it up to that single Counter.js component.


// import Redux
import { useSelector, useDispatch } from "react-redux"

// import the action methods
import {
  startCount,
  incrementCount,
  decrementCount,
  resetCount
} from "../actions/CounterActions"

function Counter() {
  // move state to Redux methods
  const counter = useSelector(state => state.counter)
  
  // set a simpler name for dispatching actions
  const dispatch = useDispatch()
  
  // insert the dispatch call into the call to set the default count
  const getStoredCount = () => {
     dispatch(startCount())
  }

I've redacted much of the code that's unrelated to this post and included the relevant lines. We import Redux, import the action methods, and then dispatch those actions inside of the components.

© 2020