My misadventures with the useSelector hook
Tags: beginners, react, redux, javascript
Published: 2022-06-03 16:47:28

One of the more interesting aspects of completing my React/Redux project was learning about the mechanics of state. 

##What is state and why did I need it?

React **state** is a JavaScript object that contains information that is private and fully controlled by the component. The Redux library allows for a global application state. Instead of (or, sometimes, in conjunction with) each component's local state, there is one object that contains all the state for the application. This object is located in the Redux **store**. 

I decided to use Redux Toolkit to help set up the global state of my application. While all the information contained in the state is located in the store, an individual component may not need the entire state object, but only a piece of the information it contains. 

Redux Toolkit conceptualizes these "pieces of state" as **slices** and provides the `createSlice` function as a way to assemble the application state one slice at a time. Slices are organized by the different features of the application, so that each slice contains only the initial state that is relevant to a specific feature. 

Physically organizing the slices that make up `state` into features helped me understand what information was better stored in local vs. global state. This separation also made it easier to visualize the discrete steps of each feature and the corresponding actions + reducers I needed to write.

When it comes down to using data from the global state, it is best practice to write selector functions. The React-Redux library provides the `useSelector` hook, allowing you to use the selector function within a component. The selector takes *the entire Redux store state* as its argument, reads (and/or derives) some value from the state, and returns the result. According to the [Redux docs](https://redux.js.org/style-guide/#keep-state-minimal-and-derive-additional-values), using selector functions keeps state minimal and easy to read, while making sure that original state is not being replaced. 

##How did I implement state?

In my React/Redux app, the two major features, for which I need access to the global store, are loading the levels on the Home page and letting users submit their own levels.

To implement these features, I created two slices: `levelsSlice.js` and `formSlice.js`. The former GETs game levels from the API and stores them in the `state` object, while the latter handles POSTing user-submitted data. State is structured thus: 

```
{
    levels: 
        {loading: false, hasErrors: false, levels: []},
    form: 
        {loading: false, hasErrors: false, message: ""}
}
```

In addition to generating and exporting actions, the thunk action, and the reducer itself--I decided to create the selector functions in these files, as well. Here is the code for `levelsSlice.js`: 

```
export const levelsSelector = state => state.levels 
```

Frankly, the levelsSlice was the first slice I created, so I relied heavily on the [Redux Toolkit "Getting Started"](https://redux-toolkit.js.org/introduction/getting-started) guide. In other words, I knew what this code was supposed to do, but I didn't know how it worked. 

Well, this initial setup got my app to work perfectly insofar as it fetched the correct data and saved it to the store, so users could choose and play levels. 

My next task was to make it possible for users to submit their own levels. On to `formSlice.js`. I more or less followed the same process for writing the thunk, the reducers, etc as in levelsSlice--with one small change:

```
export const formSelector = state => state.message
```

My reasoning: I would need the message to display as a validation to the user, so I should read it from the `state` with a selector.  

Again, everything worked perfectly. A user could submit a hint and a word, this data would be POSTed to the API, and--upon returning to the Home page, where all the levels are displayed--the user-submitted level would appear, ready to play. 

However, in the console I was getting an error to the effect of `unable to deconstruct property 'message' (something, something) undefined`. The error pointed to the following line:

```
const { message, loading, hasErrors } = useSelector(formSelector) 
```

##What went wrong?

First, I compared formSlice and levelsSlice, looking for any syntactical errors I may have made that would cause the code to break. Finding none, I tried to assign each property to a constant individually and see if it was just one not being assigned properly (meaning the problem could be in one of the reducers). All three lines gave the same error. After a couple more fruitless attempts at debugging, I googled the error and looked through some Stack Overflow posts. 

One such post in particular (titled **UseSelector State is Undefined**)--while not directly answering my question--gave me an idea that sparked my understanding of the problem (and, subsequently, its solution). A reply suggested that OP should "[a]dd a console for debugging and check the `state` object." I did so with the following line of code:

```
useSelector((state) => console.log(state))
```

Thereafter, I (as expected) saw logged to the console the `state` object, whereupon I realized my folly. 

I hadn't realized that the selector function accepts **the *entire* state**. In `levelsSlice.js`, I mistakenly assumed that the `state` object I used in the selector was the specific slice of state represented by the initial state I had defined in `levelsSlice.js`. I must have gotten confused by the fact that the name of the slice (and, hence, the key in the global state that points to the slice's properties) was the same as the key for the `levels` array. 

The line in which I deconstruct the properties `message`, `loading`, and `hasErrors` returned `undefined` because `state.message` does not exist. What I really meant was `state.form.message`.

##How did I fix it? 

At this point, I understood that the actual point of the selector in `formSlice.js` was to select the slice of state that stores the properties relevant to the form feature (i.e., `state.form`). Using the object destructuring syntax, I can then assign the value of each of those properties to a constant in my form component. With that newfound knowledge, I refactored formSlice like so: 

```
export const formSelector = state => state.form
```

Using this selector function in the **useSelector** hook would return the following object: 

```
{ message: "", loading: false, hasErrors: false } 
```

And logging `message`, `loading`, and `hasErrors` to console would allow me to see those values and how they change before, during, and after a user submits the form.

Debugging this error was one of the more fun parts of building my project. Having recently watched the film "Murder on the Nile", I felt like Hercule Poirot, following the clues until I eventually caught the culprit and solved the mystery. Thankfully, the only thing killed in this case was time.