kokobob.com

Mastering Multiple Actions in Redux Observables with RxJS

Written on

Chapter 1: Introduction to Redux and RxJS

After months of research, I've compiled this guide to help you navigate the complexities of spawning multiple actions using Redux Observables and RxJS.

If you're seeking a quick fix, here's the TL;DR: You can utilize either of() or from() combined with switchMap() or mergeMap() to initiate multiple actions.

For those interested in deeper insights, let's explore Redux, Redux-Observable, and RxJS.

Section 1.1: Understanding Redux and Redux-Observable

Many are familiar with Redux, a state management library rooted in the Flux architecture. However, Redux-Observable may be less known. In essence, Redux-Observable acts as an intermediary, enabling RxJS Observables to feed data into the Redux store.

What are RxJS Observables, you ask? They are primarily associated with Angular but can be employed across various JavaScript frameworks. Observables are entities that emit a sequence of values to subscribers, which can also include other observables. While I won't delve into the technical intricacies here, it's important to note that they serve a crucial purpose.

Observables shine in React and Redux when managing state changes that stem from non-user actions. For instance, in a gaming scenario with a timer, you might use an Observable to relay "ticks" back to Redux. In my work, we leverage Redux-Observable to handle real-time data streamed via WebSocket.

Section 1.2: The Structure of an Epic

In Redux-Observable, an epic is designed to create the observable and facilitate the publication of actions to the Redux reducer. Here's a straightforward example adapted from the RxJS documentation:

import { ajax } from 'rxjs/ajax';

// action creators

const fetchUser = username => ({ type: FETCH_USER, payload: username });

const fetchUserFulfilled = payload => ({ type: FETCH_USER_FULFILLED, payload });

// epic

const fetchUserEpic = action$ => action$.pipe(

ofType(FETCH_USER),

mergeMap(action =>

map(response => fetchUserFulfilled(response))

)

)

);

// later...

dispatch(fetchUser('torvalds'));

This code listens for dispatched Redux actions, specifically looking for a FETCH_USER action type. Upon detection, it triggers a fetch request and subsequently dispatches a "fulfilled" action with the received data. While utilizing an RTK Query endpoint might be more effective, this example elucidates the core concept.

Chapter 2: Practical Examples

In the video titled "Ben Lesh - Async Redux Actions With RxJS," you can find an in-depth discussion about handling asynchronous actions in Redux using RxJS.

Section 2.1: Conditional Data Retrieval

Suppose you have the user data, but you need to fetch additional information only if the user has admin privileges. How can this be achieved? This post aims to clarify that process. It may seem straightforward, but the RxJS documentation can be overwhelming, making it challenging to pinpoint the appropriate method for your needs.

Consider the following example:

import { ajax } from 'rxjs/ajax';

// action creators

const fetchUser = username => ({ type: FETCH_USER, payload: username });

const fetchUserFulfilled = payload => ({ type: FETCH_USER_FULFILLED, payload });

// epic

const fetchUserEpic = action$ => action$.pipe(

ofType(FETCH_USER),

mergeMap(action =>

mergeMap(response => {

const newActions = [fetchUserFulfilled(response)];

if (response.isAdmin) {

newActions.push(getAdminStuff(response.id));

}

return from(newActions);

})

)

)

);

// later...

dispatch(fetchUser('torvalds'));

The key here is switching from map to mergeMap. While map always returns a single value, mergeMap allows for emitting multiple values, which is essential for this scenario. By using an array to accumulate actions, we can dynamically determine whether to fetch admin data.

Section 2.2: Data Loading Post-Authentication

I faced a situation where I needed to reposition some data-loading actions to execute only after successful authentication and the establishment of a WebSocket connection. Previously, we occasionally dispatched data requests prematurely, leading to subtle bugs.

Here's how this can be structured:

import { ajax } from 'rxjs/ajax';

// action creators

const doAuth = (username, password) => ({ type: DO_AUTH, payload: { username, password } });

const userAuthorized = payload => ({ type: USER_AUTHORIZED, payload });

// epic

const fetchUserEpic = action$ => action$.pipe(

ofType(FETCH_USER),

mergeMap(action => {

const { username, password } = action.payload;

doAuthorization(username, password).pipe(

mergeMap(authData => {

return of(userAuthorized(authData), fetchUser(username), getCatalog());

})

)

})

);

// later...

dispatch(doAuth(username, password));

In this example, we utilize of() to create our observable sequence, as we can anticipate the number of additional actions required. Furthermore, there's no need to manually dispatch the fetchUser action from a view; itโ€™s automatically managed after logging in.

I hope this guide proves beneficial to those who have struggled to piece together available resources or for those new to Redux-Observables. If you found this helpful, please leave a clap or comment to support my work.

In Plain English ๐Ÿš€

Thank you for being part of the In Plain English community! Before you leave, consider following us on: X | LinkedIn | YouTube | Discord | Newsletter. Explore our other platforms: Stackademic | CoFeed | Venture. More content available at PlainEnglish.io.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Unleashing the Power of Imagination: Transforming Thoughts into Reality

Explore how imagination can reshape your life and learn six innovative strategies to enhance your creativity.

Finding Balance: Embracing Alcohol-Free Choices and Enjoyment

Exploring the choice to limit alcohol consumption while respecting personal preferences in a society that often promotes drinking.

# Overcoming the Challenge of Forgiveness: 5 Key Reasons

Explore five significant reasons that make forgiveness challenging, and understand the importance of letting go for your own well-being.

The Influential Thinkers Who Shaped My Learning Perspective

An exploration of key thinkers who have influenced my philosophy of learning and skill acquisition.

Exploring AI Vocabulary: Expand Your Knowledge and Insights

Dive deeper into AI concepts and terminology while exploring the future of intelligent technology.

A Comprehensive Overview of Cancer: Understanding and Combatting It

An exploration of cancer's genetic and metabolic origins, prevention strategies, and current treatment approaches.

Unlocking the Secrets of the Vagus Nerve: 4 Key Breathing Techniques

Discover four effective breathing techniques to stimulate the vagus nerve and enhance your overall well-being.

What Intelligent Life Beyond Earth Might Look Like

Exploring the characteristics and evolution of possible intelligent extraterrestrial life forms.