15
RouteManager UI coding patterns: Immutability
This is an 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.
(last update: 2021, July)
We guarantee objects' immutability through ESLint. We use the no-param-reassign rule with the following configuration
'no-param-reassign': [
'error',
{
props: true,
ignorePropertyModificationsForRegex: [
// standard array.reduce
'acc',
// array.reduce with params named differently from `acc`. They must end with `Acc` at least
'Acc$',
// standard Immer draft
'draft',
// Immer drafts
'Draft$',
// refs passed around hooks
'Ref$',
// parameters prefixed by `mutable`
'^mutable',
],
},
],
Array.reduce
accumulators can be mutated, if named acc
or suffixed by Acc
.// ❌ don't
[1, 2, 3].reduce<number>((map, item) => {
return map[item] = item
}, 0)
// ✅ do
[1, 2, 3].reduce<number>((acc, item) => {
return acc[item] = item
}, 0)
[1, 2, 3].reduce<number>((mapAcc, item) => {
return mapAcc[item] = item
}, 0)
Immer' drafts can be mutated, if named
draft
or suffixed by draft
.// ❌ don't
const next = produce(prev, temp => {
temp.message = message
})
// ✅ do
const next = produce(prev, draft => {
draft.message = message
})
const next = produce(prev, emailDraft => {
emailDraft.message = message
})
React's refs can be mutated, if suffixed by
Ref
.// ❌ don't
export function useNow(now) {
useEffect(() => {
now.current = Date.now()
}, [])
}
export function useNow(ref) {
useEffect(() => {
ref.current = Date.now()
}, [])
}
// ✅ do
export function useNow(nowRef) {
useEffect(() => {
nowRef.current = Date.now()
}, [])
}
The arguments of a function can be mutated, if prefixed by
mutable
.// ❌ don't
export function setToday(dates) {
dates.today = new Date()
}
// ✅ do
export function setToday(mutableDates) {
mutableDates.today = new Date()
}