As React applications grow larger, and more complex, sharing and passing state and props from a child component to a grandparent component and onto a separate grandchild component can be a cumbersome chore. Often times this complexity can lead to bugs in your program that are difficult to trace, as you have to check multiple locations in different files for behavior that is giving you the undesirable results.
Fortunately for us developers, Redux greatly simplifies this process by taking most of our local state, and keeping it in a 'store' for us at the application level. This is advantageous for a number of reasons. Firstly, it becomes a breeze to pass state from a child component, to the store, and then to a separate component. Secondly, it streamlines the debugging process, because the store acts as a single source of truth regarding the current state of our application.
Redux is a powerful open-source JavaScript library that we can utilize to manage application state.
Within Redux, there are a multitude of ways to implement this wonderful library. The Redux Core library gives great freedom to the developers and enables you to have precise control over each individual aspect of it's setup. This is a wonderfully flexible approach and it empowers developers to exercise absolute control over Redux's setup and implementation in their app. However, the setup can be tedious- with the structure spanning multiple files in multiple directories. The verbosity can act as a barrier of entry for those developers who are trying to avoid a complex application and wish to have a simpler, more streamlined approach.
Redux Toolkit is an excellent way to include the functionality of the Redux library with less setup, and abstraction that mitigates a lot of boilerplate code writing for you.
My favorite part of using redux is using Slices.
Now, what is a slice? A slice is a a 'slice' of state. For example, in my application, I am using state to manage Posts and Comments. In my redux directory, I have a Post Slice and a Comment Slice. As you may guess, the Post slice file houses the thunks to fetch post data from my api. The slice also will contain the reducer logic to return data payloads to the store.
On the flip side, my comment slice will contain those same items- but relating to the comments instead.
Lets talk about the different components within Redux.
Firstly, we have the Actions. Actions are a plain JavaScript object that have a type key and a payload. The type indicates what kind of action it is. For example, the action for retrieving posts from an API might have the type: GET_POSTS. When the action is passed to our slice, the slice will look at the type and decide which reducer to pass the payload to.
The payload of the action is where we store the data we are sending or receiving. In the aforementioned action { type: GET_POSTS }, my payload contains an array of post objects.
{type: GET_POSTS, payload: [ {postOBJ1}, {postOBJ2}, ect...] }
The payload value can be a string, an array, an integer, a boolean, or even an object!
So how do we pass our object to our slice?
We dispatch it!
Dispatch is a Redux method that accepts an action object as a parameter. The only way that we can update the state of our Redux store is to dispatch an action to our reducer. Dispatching can be though of similar to an event listener. When a change in state happens, and we want that change to be reflected in our store, we dispatch the action containing the value we wish to pass to our store.
Now where does the reducer fit in?
A reducer is a function that takes current state and an action as parameters. The job of the reducer is to return state.
So when we pass our GET_POSTS action to the reducer, we can write logic to take the action payload data and return that data to our store.
For example, when I fetch my posts from my API, the action.payload contains the array of post objects. In my GET_POSTS reducer, I have this following logic:
return state = action.payload
This ensures that my payload of Posts will end up in my store, making those posts accessible to the components in my React app.
Now we generally don't want to mutate state to keep our application bug-free.
However, when we are using Redux Toolkit, the createReducer and createSlice functions use a library called Immer. What this enables us to do is write logic that typically would mutate state. Instead of directly mutating state, however, Immer makes use of proxy objects and keeps track of our changes.
So within the context of my slice, I am able to write code such as:
state.push(action.payload)
to return state to my store!
How cool is that?!
I highly recommend taking a deeper dive into the Redux Toolkit documentation to see how you can put this powerful library to work in your own application!
Top comments (0)