Redux is one of the most popular technologies for the management of shared state across entire React applications, which can be complemented by Redux Observable to describe asynchronous side effects with RxJS. This approach, however, adds cognitive load when balancing the varying concepts across these three libraries. What if we could use RxJS exclusively for managing state in our React apps? This talk will demonstrate this possibility and the benefits it provides.
4. I’m a developer who works with various
technologies and languages, but primarily
JavaScript and C#
5. I’m a developer who works with various
technologies and languages, but primarily
JavaScript and C#
I have gained experience at the likes of Sky,
Channel 4, Trainline, News UK, and NET-A-
PORTER
6. I’m a developer who works with various
technologies and languages, but primarily
JavaScript and C#
I have gained experience at the likes of Sky,
Channel 4, Trainline, News UK, and NET-A-
PORTER
I love open-source software, writing, speaking,
and mentoring
16. On the client, it uses:
● React for rendering the DOM
● Redux for state management
17. On the client, it uses:
● React for rendering the DOM
● Redux for state management
● RxJS for reactive data transformation
and aggregation
18. On the client, it uses:
● React for rendering the DOM
● Redux for state management
● RxJS for reactive data transformation
and aggregation
● Redux Observable for expressing
async Redux actions with RxJS
22. “RxJS is a library for [functional], reactive
programming using Observables, to
make it easier to compose
asynchronous or callback-based code.” -
the RxJS team
66. So we can use the same paradigms to:
● create and query data sources
67. So we can use the same paradigms to:
● create and query data sources
● combine said sources
68. So we can use the same paradigms to:
● create and query data sources
● combine said sources
● reduce actions into a single source of
truth
69. So we can use the same paradigms to:
● create and query data sources
● combine said sources
● reduce actions into a single source of
truth
● consume this source of truth in React
87. Summary
● RxJS provides a functional, declarative means
of consuming and aggregating data sources
88. Summary
● RxJS provides a functional, declarative means
of consuming and aggregating data sources
● Redux Observable is nice, but we can cut out
the middle man using HOCs and Hooks
89. Summary
● RxJS provides a functional, declarative means
of consuming and aggregating data sources
● Redux Observable is nice, but we can cut out
the middle man using HOCs and Hooks
● However, Redux provides a (positively)
opinionated architecture
90. Summary
● RxJS provides a functional, declarative means
of consuming and aggregating data sources
● Redux Observable is nice, but we can cut out
the middle man using HOCs and Hooks
● However, Redux provides a (positively)
opinionated architecture
● How does this perform compared to Redux?
Hey everyone! Welcome to my talk on Managing State in React Apps with RxJS
Hello!
I’m James!
I’m a developer who works with various technologies and languages, but primarily JavaScript and C#
I have gained experience at the likes of Sky, Channel 4, Trainline, News UK, and NET-A-PORTER
I love open-source software, writing, speaking, and mentoring
I work at YLD
We’re a software engineering and design consultancy
We specialise in JavaScript, TypeScript, Node.js, React, DevOps, and beyond!
Just a couple more things before we jump in: firstly, I’ve been ill throughout this entire conference, so I apologise in advance if I start spontaneously coughing.
Finally; a huge thanks to FrontCon for having me back and for organising yet another stellar event
Time for some background (see what I did there?)
Recently, I have been contributing to a web app.
On the client, it uses:
React for rendering the DOM
Redux for state management
RxJS for reactive data transformation and aggregation
Redux Observable for expressing async Redux actions with RxJS
That sounds like a lot to juggle! How does that even look?!
I’ll show you, but let’s firstly take a step back.
What is RxJS?
“RxJS is a library for [functional], reactive programming using Observables, to make it easier to compose asynchronous or callback-based code.” - the RxJS team
Right. How does that translate to code?
Note that I’m using TypeScript here to clarify the shape of the object which should be emitted by the web socket observable. webSocket creator included in RxJS. pipe method on stream used to forward emissions to sequential operators. Scan is like Array.prototype.reduce. Observables are lazy and thus won’t be executed until one calls subscribe.
loadStory uses fromEvent observable source creator. Concat => one emission for each inner observable, thus map and renderComponentFromData will be called twice
So I can generate, consume, and map streams of data, without side effects, using composable operators?
Yup! Pretty neat, right?
You can also write your own observables!
This is COLD/UNICAST
This is COLD/UNICAST
This is HOT/MULTICAST
This is HOT/MULTICAST
Great, but what if I need to push data to subscribers from elsewhere?
RxJS has subjects!
(It’s an observable + observer, all in one lovely API surface)
I should mention there are special kinds of subjects which we will cover later
How can I consume observables in my React app?
How About Redux Observable?
This is COLD
N.B. isActionOfType is a TypeScript type guard, in case you’re wondering
EPIC. Almost analogous to Redux Thunk. Actions in, actions out! Describe body!
How do we integrate Redux Observable into Redux? With Middleware! createEpicMiddleware - I love that term
Great, so I can use RxJS to control my Redux state, which I can render with React!
But...
...I have to use it alongside Redux and Redux Observable.
What if I could just use RxJS for everything?
Well, I tried just that. Let me show you.
Disclaimer: it’s a proof-of-concept. Don’t get the pitchforks out just yet.
Ron Swanson Quote - never have truer words been spoken
Show validation failure state
Here’s our root App component
Here’s what the message list looks like. It’s a stateless component that consumes messages via its props and renders them. But how do we connect them to the state?
Notice this connectToObservable bad boy? Before diving into the implementation, here’s what our app’s state looks like
Going back to those special kinds of subject I mentioned earlier: BehaviorSubject - sends the most recently broadcast value to new subscribers. How does connectToObservable subscribe to the appstate stream?
connectToObservable is a higher-order component that takes in a component and returns a new one, holding its own state using React’s useState hook (which Manjula covered yesterday). There’s also a call to React.useEffect. This hook is used to manage side effects between prop changes, or in our case, when the component mounts and unmounts; this is determined by the empty array of side effects as the second param to useEffect. Thus, when the HOC mounts, it will subscribe to the observable, and will unsubscribe when unmounted.
Reading state is cool, but how can we update it?
Let’s take a look at our form component more closely. When submitted, we call addMessage; as we’ll see shortly, this returns a reducer function. Said function is passed to toNextState, you can think of this as Redux’s dispatch
So how does toNextState work? It will take the latest app state via the appState stream and pass it into the reducer, whose emissions will then be pushed back to the app state. To clarify, let’s take a look at a reducer. Oh, and if you’re wondering why withState is exported, we’ll hit that shortly.
addMessage is what I like to call an action-reducer. It’s a function that is invoked to trigger a side effect in the app’s state, returning a reducer function which takes in state, and produces an updated state as a result, wrapped in an observable (EXPLAIN OF)
Why do reducers have to return observables? (Not a joke)
So we can express asynchronous effects!
Here’s what’s called when we click the button to add a Ron Swanson quote. Looks similar to addMessage, right?
Well in this case, our action-reducer returns an observable created with concat, so we can emit respective loading, success, and error states. Now do you know why we export withState, so we can get the most recent state between broadcasts!
So we can use the same paradigms to:
create and query data sources
combine said sources
reduce actions into a single source of truth
consume this source of truth in React
But how does this perform compared to Redux?
Well, the useReducer hook (LOL). I ported this app to use it in lieu of RxJS as a basis of comparison. Explain useReducer!!!
Y axis is megabytes!
MIGHT BE
MIGHT BE
Spend a little more time in the overall side effect (few extra MS?)
Call stacks are crazy
MIGHT BE
MIGHT BE
So we’re potentially hampering performance.
Someone: “But I like the approach. How do I go about ditching Redux?”
Well, you probably shouldn’t.
RxJS can be overkill for simpler applications.
Plus Redux provides a solid, opinionated architecture.
Someone else: “Isn’t MobX built around observables? Why not just use that?”
It is, and it’s great, but its observables are not compatible with RxJS (so bear that in mind)
Summary
RxJS provides a functional, declarative means of consuming and aggregating data sources
Redux Observable is nice, but we can cut out the middle man using HOCs and Hooks
However, Redux provides a (positively) opinionated architecture
How does this perform compared to Redux?
Final thought
I think React’s ability to handle any input objects without wrapping them into observables/wrappers/trackers is significantly underappreciated. That’s why I think the connectToObservable HOC is a good approach for separating presentation components from stateful logic