Dev Diary 2020.04.05 – Reducers - davidhorm/wavelength GitHub Wiki
Aside: I used Material UI , and that seems to give some stylings within Storybook. Enough for me not to puke when looking at Times New Roman. Okay, on to Reducers.
I'm going to control state by using React's useReducer. p.s. useReducer vs useState in React pretty much says you should useReducer
if you got fancy state happening. I'm using Typescript, so to look for inspiration on how to do it properly, I read up on Redux's Usage with TypeScript for inspiration.
Instead of typeof
, I wanted to use Typescript String Enum to describe the action types. I used interface
to describe the state and action types. And I created an object of functions for action creators. My unit tests were testing basic reducer functionality, but more importantly, how the action creators interact with the reducer.
And got all my tests running awesome.
This is sort of a lot of boilerplate, that would normally go away had I used Redux. But here it is, warts and all, when building it from scratch. If I wanted to create a new action, then I'll need to:
- add an action type
- define an action type interface
- add an action creator
- implement reducer logic
Is there a better way?
I happened upon Wrangling useReducer, from action creators to typings while researching something else. It describes how action creators were ways to safely create properly typed actions. And there should be some advantages since I'm using Typescript right?!
- Replace
interface WavelengthState
withtypeof initialState
for typing. - Replace Action Types and Action Creators with Typescript types.
Yeah! That makes the reducer file from ~60 to ~40 lines. But can I replace the enum?
I don't even need those enums. Because Typescript will highlight case statements that aren't defined in the type.
But now I'm realizing that I can't really use objects using this destructured array style of defining types. So back to types of objects. So now I have something like the following:
export const initialState = {
pointerPercent: 0,
...
};
type actions =
| { type: 'RESET_GAUGE'; targetPercent: number }
...;
export const reducer = (state: typeof initialState, action: actions): typeof initialState => {...};