Redux is inspired by Flux, which was developed by Facebook. Unlike Flux, Redux is quite flexible and does not require any specific infrastructure like GraphQL. We will use Redux in combination with Onsen UI to build a simple Calculator mobile app. One of the nicest things about this app is that it will look native, both on Android and iOS, due to Onsen’s autostyle feature.
All the source code is freely available at https://github.com/philolo1/OnsenUI-redux-calculator/.
Let’s first see what Redux is and how it works. Redux consists of three main components:
- Store: This structure stores the complete state of our application. Given only the content of the store, the application should be able to save and recover the current state of the application.
- Actions: Actions are how the application interacts with the store. The application sends an action with some attached data. These actions are than handles by a so called reducer.
- Reducer: The Reducer is a function that takes the current state and an action and transforms it to a new state.
In addition to these three components, there are three principles of how a redux application should be written.
- Single Source of Truth: As mentioned previously the store is the only place where data is stored. This enables the application to do nice things like undoing an action and also helps to more easily debug.
- The state is read-only: The state of the application can only be changed via actions. This is very useful for debugging, since the changing state flow is much more clear.
- The reducer consists only of pure functions: Pure functions are functions that do not change the parameter object they are given.
The first two points should be very clear. For the second one lets have a look at what a pure function is. Let’s say we want to create a function
handleLoaded, that should add the property
isLoaded: true to the state:
As you can see, we need to be careful to write pure functions and don’t manipulate the parameters. If the function wasn’t pure, it would be hard to recover the previous state and would make debugging much harder because of side effects.
Calculator: HTML + CSS
Now that we have understood the basics, let’s create our Calculator app. The calculator consists of 6 rows: The first one will be a simple
div that contains the display, the remaining rows will consist of buttons of the calculator. For simplicity, we will only support integer manipulation. Combined with the power of
ons-page we get:
There is now real magic going on here. Every row is split equally across the screen and every column has equal height using flexbox and percentages. The colors of the buttons are done by different opacity. CSS contains only a few lines of code:
TYPE: This action indicated that a number is typed on the calculator.
CHANGE_SIGN: This action indicates a change of the sign (‘+’/‘-‘) of the display.
CLEAN: This action will reset the calculator.
EQUAL: This action will be triggered when the
OPERATION: This action will be called whenever we press an action button that will do a mathematic operation with two operands.
The Redux Framework manages the store. We will need to give it our reducer with
Redux.createStore(ourReducer), which we will define later. Since we want to rerender every time the state changes, we need to listen to the store. Fortunately, Redux provides us with a function
store.subscribe to which we pass our render function.
The complicated part is writing the reducer. Our reducer will have four states:
number: This represents the number that will be displayed on the screen.
operation: This will store the last operation function, that has been calculated like plus, minus etc.
storedFunc: This function will be used to store results and operations that are not directly displayed. For example, if we type
1 +, the value of the storedFunc will be
(x) => 1 + x. This makes evaluation quite easy since we have to only call
originalFunc: This function is necessary to support repeating the last operation for the ‘=’ sign.
lastAction: This piece of data should contain the last action that has been done.
Now that we have the state and actions, we only need to write the reducer. We will split our reducer into two, one for adding the lastAction and the other one doing the main state transformation.
Next, we will write our general reducer that handles all the actions. We will split the reducer up into multiple functions:
It should be noted here that at the beginning of our application, the state will be undefined, that is why we need to define our initial state with
number: 0 to display 0 at the beginning. Now we need to define the
handleOperation function. As stated previously we take advantage of our
And now we are done and have our app perfectly working! It might take a while to get used to this code thinking, but we could give you a small glance at the word of redux and functional programming.