Redux state variable naming
— redux
Redux reducers can call other reducers, requiring variables to store intermediate steps of state. What should these intermediate state variables be called? I have tried a few different naming styles over the years, and now have settled on a style which I think is very convenient. Skip to the end if you just want the final optimal style, because I'm going to describe the previous styles I tried first.
Style 1: With Lots of Extra Typing
It's 2016. The gorilla is dead. I'm working on my first non-trivial project using redux.
Not sure what inspired this style, but I started to name the intermediate state variables after the last change that happened e.g:
1const stateWithFriends = getFriendList(state);2const stateWithSortedFriends = sortFriends(stateWithFriends);3const stateWithResult = playGame(stateWithSortedFriends);
With with with. With is a short word, but still these variable names are quite long. Also the variable name is often similar to the name of the function it gets it's value from, so not adding much useful information. Considering these issues I now rate this style as ok, so so, tepid.
I stuck with this scheme, and variations of it, for a few years. I'm glad I stuck with it for so long, as the next style I tried had a serious flaw.
Style 2: A Sense of Order
Maybe I was motivated to gain some efficiency, or maybe the lead paint in the office was starting to get to me. Either way I started using a new naming style:
1const state2 = getFriendList(state);2const state3 = sortFriends(state2);3const state4 = playGame(state3);
Shorter variable names! No thinking required! This must be an improvement, right?
No. This style has a massive flaw: Inserting a new step means you have to rename all the state variables that follow. e.g
1const state2 = getFriendList(state);2const state3 = getEnimiesList(state2); // new step inserted3const state4 = sortFriends(state3); // so i had to rename this variable and param4const state5 = playGame(state4); // and this one, and any others that follow
Ugh what a waste of time. It's also easy to miss renaming a variable, leading to bugs which can be hard to spot.
This naming style is very suboptimal and should not be used. I feel bad inflicting this on my colleagues, but one of them (hi Steve!) did come up with a more efficient way of inserting a new step, which I spotted during a code review:
1const state2 = getFriendList(state);2const state2a = getEnimiesList(state2); // <-- #innovation3const state3 = sortFriends(state2a);4const state4 = playGame(state3);
2a
?! Initial horror quickly turned into admiration. They had found a simple solution to the renaming problem. Like turning a single house into two flats, it can be done with only a small inconvenience to the neighbours.
Final Form: Be Divine, Rebind
The redux immutability rules only apply to values. Variable names are irrelevant when checking an object for changes. This means we can declare a variable using let
and reuse that variable for our intermediate state steps e.g
1function reducer(state, action) {2 let result = state; // result is the variable we are going to reuse34 if (action.type === "FOO") {5 result = doStuff(result);6 result = moreStuff(result);78 return result;9 }1011 return result;12}
No thinking about variables names! No mass renaming when inserting a new step!
This superficially looks like we are breaking redux immutability rules, but we can check it's ok using a test:
1const initialState = {2 count: 13};45const INC_ACTION = 'INC';67function inc(state) {8 if (state.count > 2) {9 return state10 }1112 return {13 ...state,14 count: state.count + 1,15 };16}1718function reducer(state = initialState, action) {19 // immediately assign to new variable so we can consistently refer to state as result for the entire reducer20 let result = state;2122 switch (action.type) {23 case INC_ACTION: {24 // we can reuse the result variable to pass latest state around and to save the output25 result = inc(result);26 result = inc(result);2728 return result;29 }30 }3132 return result;33}3435test('can reuse variable name without breaking the immutability rules of redux', () => {36 const secondState = reducer(initialState, { type: INC_ACTION });3738 // a new object was returned because state has changed39 expect(secondState === initialState).toBe(false);40 expect(secondState.count === 3).toBe(true);4142 // now because of the condition check in inc() the state object will not change as count > 243 const thirdState = reducer(secondState, { type: INC_ACTION });4445 // underlying state object is still the same46 expect(thirdState === secondState).toBe(true);47 expect(secondState.count === 3).toBe(true);48});
Convenience achieved.