Let’s look at the first of the screens we need to build for our application - the Add Word screen, used (surprisingly enough) to add a new word to the list of words we’re currently viewing.
Before we can start writing code, we need to do a little bit of design: what do we want this screen to look like?
Here's a mockup of one possible design. It's deliberately a low fidelity image, spelling mistake and all, intended to start a discussion about the user experience.
I've found the putting together a polished mockup invites debate about font choices, colours, and spacing of elements. It seems that people get distracted by "shiny" and stop thinking about the important issues - such as whether the UX will deliver what the users actually need. This even applies to experienced subject matter experts.
We can start by declaring the properties that our screen needs to expose:
We start each property with an empty string so that we never need to deal with nulls.
Our constructor is straightforward - in fact, we could have omitted it completely.
For each of the properties, we follow the convention we’ve already established, providing a
WithXXX() method that returns a near-clone of the original.
I’ll skip over the implementations of
WithPronunciation(), jumping straight to the private constructor that makes them possible:
You’ll note that we don’t have any provision here for undo or redo, even though those were shown in the mockup. We’ll come back and put those in later on, once we’ve got a few more moving parts hooked up.
Recall that the Redux model revolves around messages that are sent to our central store, with reducers that apply those message to our current state.
Let’s create a trio of messages that can be used to update our AddVocabularyWordScreen as the user makes changes. Here’s the declaration of
The message contains just what we need, nothing more. The implementations of
ModifyPhraseMessage are similarly simple.
We can now start on our
ScreenReducer class, used to combine screens and messages. Our entry point is based on implementing the
For each kind of screen, we’ll delegate out to a specified private reducer method:
In this case, the handling of each message is simple, so we do it inline. For more complicated situations, we would break the logic out into a dedicated method for that one case.