When we first started designing our developer dashboard and aligned on using Redux for state management, we faced the question many developers face when building React apps: where do we put the side effects?
Side effects are basically anything that affects something outside of the scope of the current function that’s being executed. In our dashboard, this includes:
In the context of our app, this looks like:
Well, not in reducers.
Reducers — functions that we use to update our app’s state given its current state and an action — are pure functions. They cannot contain side effects like making API calls to our backend service.
So, where do we put the three side effects listed above when a REGISTER_APPLICATION event is dispatched to our Redux store?
When thinking about side effects in React apps, we thought about the following constraints:
We looked around for what was popular with the React community and found two options that could hit our criteria: Thunks and Sagas.
The first option we looked into was Thunks. Thunks transform action creators so that they can return functions (rather than JSON objects representing actions). We can then use these functions to make API requests and trigger dispatch calls to our redux store.
The benefit of using Thunks is that they are lightweight and easy to integrate into a React-Redux application. However, Thunks require us to mock our APIs to test.
This complicates testing — and makes it a lot less fun.
Now for Sagas!
There are a few things that make Sagas different. Most importantly, they’re heavier than Thunks (we add a middleware layer to our React-Redux app); but, they also have a whole suite of benefits that make it incredibly easy to manage side effects in our React apps.
Here are a few of the benefits:
Sagas are generator functions that listen for Redux actions. When an action is dispatched to the redux store, a corresponding Saga will execute. This allows us to pair a Saga with a particular redux action.
What made Sagas delightful for us to use was its concept of Effects. An Effect contains an instruction for the Saga middleware but does not perform any execution.
When the middleware retrieves an Effect, the Saga is paused until the event is fulfilled.
This is what a Saga to register an application looks like:
As you can see, we’ve placed all side effects for the REGISTER_APPLICATION action into a single place! And now for the test:
As we noted earlier, we don’t have to mock any of our API calls — in each line, we just check if the Effect object matches what we expect it to be.
So, to sum up what we’ve learned:
We’ll see you next time 😉
Smartcar is the connected car API that allows mobile and web apps to communicate with connected vehicles across brands (think “check odometer” or “lock doors”).