Recently I got curious about RxJS as a replacement for Redux and all the boilerplate code needed to integrate it with a React project. For this example, I wanted to create a "micro-store" and initialise it with data from the https://randomuser.me/ API.
Creating a micro store
Let's start by creating and exporting an initial state in a store/users.js
file. We will also declare a state
variable that will contain the current state of this store over time.
const initialState = {
loading: false,
users: [],
}
let state = initialState
export default {
initialState,
}
Then we will add a BehaviorSubject and initialise it with the initial state.
import { BehaviorSubject } from "rxjs"
let subject = new BehaviorSubject(initialState)
We can now add a function all subscribers can use to synchronise their state with the current state of our store, using their setState
method.
export default {
initialState,
subscribe: setState => subject.subscribe(setState),
}
Lastly, we will request users array from the API and update the content of our micro-store.
import { ajax } from "rxjs/ajax"
import { catchError, delay, map } from "rxjs/operators"
subject.next({ ...state, loading: true })
ajax
.getJSON('https://randomuser.me/api/?results=10')
.pipe(
delay(2000), // This simulate some latency
map(({ results }) => subject.next({ ...state, loading: false, users: results })),
catchError(() => subject.next({ ...state, loading: false })),
)
.subscribe()
The final content of store/users.js
is:
import { BehaviorSubject, of } from 'rxjs'
import { ajax } from 'rxjs/ajax'
import { catchError, delay, map } from 'rxjs/operators'
const initialState = {
loading: false,
users: [],
}
let state = initialState
let subject = new BehaviorSubject(initialState)
subject.next({ ...state, loading: true })
ajax
.getJSON('https://randomuser.me/api/?results=10')
.pipe(
delay(2000),
map(({ results }) => subject.next({ ...state, loading: false, users: results })),
catchError(() => subject.next({ ...state, loading: false })),
)
.subscribe()
export default {
initialState,
subscribe: setState => subject.subscribe(setState),
}
Link store to a component
import React, { useState, useEffect } from "react"
import usersStore from "./store/users"
export default function App() {
const [{ loading, users }, setUsers] = useState(usersStore.initialState)
useEffect(() => {
const subscription = usersStore.subscribe(setUsers)
return () => subscription.unsubscribe()
}, [])
return (
<div className="App">
<h1 className="text-3xl">Users:</h1>
{loading ? (
<p>Loading ...</p>
) : (
<ul>
{users.map(user => (
<li key={user.email}>{user.name.first}</li>
))}
</ul>
)}
</div>
)
}
Result
Top comments (0)