DEV Community

Nicolle Romero
Nicolle Romero

Posted on • Originally published at Medium on

Hooked on React Redux: Get your feet wet with this simple app

Redux can be intimidating and has a reputation for being hard to implement at first, but it doesn’t have to be! This simple example can help you navigate the murky waters, avoid pitfalls, and get started with Redux!

Alt Text

There’s a nice selection of options out there for managing state in React, and the solution you choose will be based on a number of factors (for example, the size and complexity of your application). This article focuses on a very specific use case and allows you to get your feet wet by refactoring a simple application to include Redux.

There’s a lot to learn from taking a fully functional application and purposefully breaking it in order to improve and grow. I gave a Lightning talk on Redux while at Hackbright Academy, and decided to refactor a short and sweet (well, maybe not so sweet 😳) app we used in a lab, called Sharkwords. The app is a hangman-style game that results in the character’s early demise if the secret word is not selected in under five guesses. Watch out for sharks…

Step 1. Gather Your State and Set Up Your Store

In Redux, the createStore function creates an object, the “store,” that holds the application state for the entire app. It’s possible to shove every piece of state in there, but it’s not absolutely necessary (if you prefer, you can manage state that’s local to a component with the useState hook instead). In this example, we store the following state in the store:

  • numWrong (i.e. the number of incorrect guesses)
  • guessedLetters (i.e. which letters of the alphabet have been guessed)
  • word (secret word hardcoded to “hello” for this simple example)

First, declare your initial state when starting a fresh game and create your store:

const { Provider, useSelector, useDispatch } = ReactRedux;

const initialState = {
  numWrong: 0,
  guessedLetters: [],
  word: 'hello',
};

...

// Create a Redux store holding the state of your app.

const store = Redux.createStore(
  reducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

// Wrap in <Provider> tags to access the store throughout the app

ReactDOM.render(
  <Provider store={store}>
    <Sharkwords />
  </Provider>,
  document.querySelector('#root')
);
Enter fullscreen mode Exit fullscreen mode

Step 2. Let’s See Some Action(s)!

It’s important to remember that the store is immutable , meaning it can’t be changed directly. So when the state changes in the app, a new state object is created (i.e., a copy is made with the minor change in it). To achieve these changes—for example when a user guesses a letter—we use actions and reducers (don’t worry, I’ll explain that in a bit). So let’s go ahead and declare two actions in our game:

...

const GUESS_LETTER = 'GUESS_LETTER';
const RESET = 'RESET';

...
Enter fullscreen mode Exit fullscreen mode

Pretty straightforward: the user can guess a letter, GUESS LETTER, or reset the game, RESET.

Step 3. Setting Up Our Hooks… Line, and Sinker!

The store has a few helper methods that make using Redux super predictable and simple to use, but we’ll focus on two Redux hooks that do a lot of the heavy lifting: useDispatch and useSelector.

The store gets information to update state from these actions, and each action has: a ‘type’ property (this is the type of action and is required) and the payload (this is the info being sent to the store and is optional). For example, when a user clicks on a letter to submit a guess, we send this information (the action) to the store using the dispatch function returned by the useDispatch hook:

const dispatch = useDispatch();

...

const handleClick = () => {
      // The dispatch function sends an action w/ a payload (letter) to the store

      dispatch({
        type: GUESS_LETTER,
        payload: letter,
      });
    };

...
Enter fullscreen mode Exit fullscreen mode

We also need to select the part of the state we’re interested in. We’ll purpose the useSelector hook to achieve this:

  const guessedLetters = useSelector(state => state.guessedLetters);
  const numWrong = useSelector(state => state.numWrong);
  const word = useSelector(state => state.word);
Enter fullscreen mode Exit fullscreen mode

So, when the user selects the letter a, an action of type GUESS LETTER is dispatched to the store with the payload of string a.

Oh no, that wasn’t a correct guess. Our swimmer looks concerned. 😐

Step 4. For Every Action, There Is a Reaction 🦈

Now we need to hook into our store and provide the instructions on how the state should be updated for each type of action. We need to give our application the instructions it needs to react to the specific types of actions, a kind of recipe. This is where the reducer comes in: just like it sounds, the reducer is a function that takes in multiple parameters and returns a single value. Let’s see how this works in Sharkwords:

function reducer(state = initialState, action) {
// Check to see if the reducer cares about this action.

  switch (action.type) {
    case GUESS_LETTER: {
      const letter = action.payload;
      const correct = state.word.includes(letter);

      return {
        ...state,
        guessedLetters: [...state.guessedLetters, letter],
        numWrong: state.numWrong + (correct ? 0 : 1),
      };
    }

    case RESET: {
      return initialState;
    }

    // Otherwise, return the existing state unchanged.
    default:
      return state;
  }
}
Enter fullscreen mode Exit fullscreen mode

First, we check to see if the action type matches the action types handled by the reducer function. If it does, we provide the logic to update state (guessedLetters and numWrong) depending on if the payload (guessed letter) is a correct or incorrect guess. The reducer returns the updated (copy) of the state or the unchanged state and React updates our components!

After four wrong guesses, our swimmer is understandably freaking out! 😱

Alas, after one more wrong guess, we’ve reached five wrong guesses and we get the bad news that we’ve lost the game. Drats! We’re then prompted to play again. The RESET action is dispatched to the store, and the initial state is restored.

You can see all of Sharkwords on GitHub. As a bonus, be sure to check out the Redux DevTools that support time travel ⏱ and hot reloading🔥!

Alt Text

(Special thanks to Hackbright Academy for allowing me to repurpose their app for this article.)

About the author:

Hi! 👋 Nicolle, here. I’m a Frontend Software Engineer that loves building in React. I’m looking for an awesome team to join, so please reach out if you’re looking to hire a 🧨 engineer!


Top comments (0)