Building a React/Redux app with RTK
For my final project at Flatiron School’s Software Enginnering program, I built a React application using the Redux Tool Kit. I am a professional touring bass player for the Colorado-based rock group “Eminence Ensemble”, and for my final project, I built a new website for the band!
Taking the leap into the RTK world was definitely a learning curve! I decided to build my app using the “modern” way, which was completely new to me. I definitely threw myself in the deep end, but after hours of reading and practice, I honestly love RTK. Here’s an overview of a few of my favorite tools that come with the Redux Tool Kit, and how I utilized them!
According to the official Redux docs,
“Redux Toolkit makes it easier to write good Redux applications and speeds up development, by baking in our recommended best practices, providing good default behaviors, catching mistakes, and allowing you to write simpler code.” They also note that it is not necessary to use RTK to build a Redux app but strongly recommended.
So what’s the big deal? RTK offers some very intuitive tools to help streamline the development process, namely configureStore(), createSlice(), and createAsyncThunk().
To begin, configureStore() wraps createStore, and simplifies the classic Redux store development by automatically combining your reducers using Redux combineReducers() to create a root reducer under the hood by passing in a reducer object as an argument to configureStore(). The reducer object takes a reducer from your slice file (more on that in a second), and lets you assign it to a key for later reference. It also allows the developer to apply any middleware they wish, but automatically comes loaded with redux-thunk and the redux DevTools extension by default. This creates a much cleaner store file:
In addition, RTK’s createSlice() greatly simplifies the development process using a few awesome abstractions. Slice in this case, refers to a specific “slice” of the redux store, as in a slice of a cake. In a blogging app, you might have a “posts” slice to reference state that pertains to posts, and a “users slice” to reference the users state. This allows the developer to easily maintain an organized file structure.
CreateSlice() accepts three arguments. The first is a name which is used as the prefix for the generated actions. The second argument is the initial state, an object which sets the properties that this slice will maintain. Finally, the third argument is your reducers, and extra reducers. Reducers is an object, which contains “case reducer” functions; the equivalent of the case statement in a classic Redux switch function. The object’s keys serve as the action type constants (called using useDispatch() later in the application) and the values represent the reducers function to be dispatched.
This is where RTK really adds some magic to the traditional Redux reducer logic. When altering state using the classic Redux patterns, it is imperative that you alter data immutably. Redux’s docs argue that
“immutability in the context of a Web app enables sophisticated change detection techniques to be implemented simply and cheaply, ensuring the computationally expensive process of updating the DOM occurs only when it absolutely has to (a cornerstone of React’s performance improvements over other libraries).”
However, with RTK, and specifically the integration of the Immer library, the developer is able to write mutative logic in the reducer, which is much cleaner and simpler for the developer to write and understand. By creating a copy of the state (known as a draft object) and comparing changes to state under the hood, Immer can take mutative logic and safely alter and return the state as if it was immutable logic. This removes A TON of spread operators which are traditionally used to write immutable logic, resulting in code that is actually readable, and quicker to write. Here is an example from my ProductSlice:
RTK allows us to easily export the reducer to feed to our configureStore():
More on the “extra reducers”, and all those statuses in a moment!
Another amazing feature that comes in RTK is createAsyncThunk(). As I mentioned earlier, redux-thunk middlewear comes preloaded in configureStore(), and it allows us to seamlessly integrate async logic into our application. createAsyncThunk() accepts two arguments, the first is an action type string, used to dispatch the action later, and the second is a callback function which MUST return a promise object. This took me a minute to wrap my head around, but ultimately simplifies async logic such as fetch().
The above function sends a fetch to add a product to my backend, and if succefull, returns a fulfilled status and the returned data. If something goes wrong it will return a rejected status and the appropriate message regarding the failure from my backend, with help from thunkAPI.rejectWithValue().
Now for the extra reducers in the createSlice() from earlier! The extra reducers allow the developer to handle the async response by creating action creators for each of the promise’s states: pending, fulfilled, or rejected.
In this case, dispatching addProduct will first run the fetch logic, which returns a promise object. Using the promise’s pending status, the action creator addProduct.pending dispatches the shop/addProduct/pending action, which sets my state’s addProductStatus to ‘loading’. Once the promise is fulfilled or rejected, the corresponding action creator will dispatch it’s corresponding action, and either update the state.products with the new data, or update the state.message with the error message, and update the addProductStatus to complete or rejected. Great! But why the status????
Using the Redux state to store a status for each fetch, I am able to easily display success or error messages, and handle redirects from other components using the useEffect() hook! Heres an example from my product form:
By using these awesome tools in the Redux Tool Kit, state management is simplified and organized. I allows the developer to focus on creating, and speeds up the workflow. For these reasons I HIGHLY recommend taking the plunge into the RTK world!
Thanks for reading!
github repo: https://github.com/Zacharyflynn06/ee-frontend