RouteManager UI coding patterns: Redux Saga
Stefano Magni
Posted on March 4, 2022
This is a non-exhaustive list of the coding patterns the WorkWave RouteManager's front-end team follows. The patterns are based on years of experience writing, debugging, and refactoring front-end applications with React and TypeScript but evolves constantly. Most of the possible improvements and the code smells are detected during the code reviews and the pair programming sessions.
(please note: I do not work for WorkWave anymore, these patterns will not be updated)
(last update: 2022, March)
- Prefer linearity over side effects
- Use call only to allow mocking the called function
- Create frontend-oriented requests
Prefer linearity over side effects
Sagas triggered as a result of a side effect are hard to follow and lead to a lot of unwanted effects.
// ❌ don't
function* foo() {
yield put({
type: 'baz',
})
}
function* bar() {
yield put({
type: 'baz',
})
}
function* baz() {
while (true) {
yield take(takeBazAction)
doBaz()
}
}
// ✅ do
function* foo() {
doBaz()
}
function* bar() {
doBaz()
}
Use call only to allow mocking the called function
Pure/simple functions that do not trigger side effects or read data from external sources should not be call
'ed, since controlling them from the tests require useless boilerplate.
// ❌ don't
function* foo(clientId: string) {
const serverId = yield call(createServerId, clientId)
const serverEntity = yield call(requestEntity, serverId)
return yield call(createClientEntity, serverEntity)
}
// ✅ do
function* foo(clientId: string) {
const serverId = createServerId(clientId)
const serverEntity = yield call(requestEntity, serverId)
return createClientEntity(serverEntity)
}
Create frontend-oriented requests
Requests should be frontend-oriented, even when the backend uses different names or a single API for multiple purposes.
// ❌ don't
function* geocode(address: string) {
yield call(geocodeAddresses, address)
}
function* reverseGeocode(latLng: LatLng) {
yield call(geocodeAddresses, latLng)
}
function* geocodeAddresses(param: string | LatLng) {
yield call(executeRequest, 'Geocoding.geocodeAddresses', param)
}
// ✅ do
function* geocode(address: string) {
yield call(geocodeRequest, address)
}
function* reverseGeocodeRequest(latLng: LatLng) {
yield call(geocodeAddresses, latLng)
}
function* geocodeRequest(address: string) {
yield call(executeRequest, 'Geocoding.geocodeAddresses', address)
}
function* reverseGeocodeRequest(latLng: LatLng) {
yield call(executeRequest, 'Geocoding.geocodeAddresses', latLng)
}
Posted on March 4, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.