We build our first state transactions as two discrete transactions, each working on a specific portion of the state. Each of these transitions are governed by an acceptable range and we want to be able to apply these limit within our model.
With our discrete transactions we see that is easy to reason about and keeps our rules local to the data being worked on, without having to be considered in other transitions or, even worse, in the eventual view layer. Patterns like this make it easier to easily transport a given data model to any view layer.
Instructor: [00:00] We have two attributes in our state. The first represents the number of moves left, while the second tracks the number of moves the player has made. Here, we're just kenny-loggings our state to the console on the right.
[00:11] Let's start building out some transactions in our answer model. We'll start by creating a limiting function that will keep stray values in check. We'll call it limitMoves. limitMoves is defined as a function that takes a function from A to number as its first argument, giving back another function that takes an A and returns us a number.
[00:32] To implement, we'll reach for this clampAfter helper, applying zero and eight is its arguments. Then we'll just pop over to helpers and see what it does. Looking at the siggie, we see our first two numbers followed by the A-to-number function, then the same A-to-number function from limitMoves.
[00:49] We take a min and a max value followed by a function and return a composition that runs that function, passing the result to a clamping function, thus limiting our number. We'll export our first transaction that will decrement our moves left when the player performs a move.
[01:06] We define our brand-new decLeft to be a function that goes from a unit to a state fixed to our appState with a unit in the resultant. To implement, we first take our unit as input. Then we'll lean on this over helper to decrement over our left attribute using limitMoves, which we preload with this dec helper.
[01:29] Over can be thought of as a targeted mini-reducer for applying a function over a state attribute. It takes a pair of string function and then an object returning a state object of unit. Using the key and function, we build an object that partially applies mapProps to be used with our state's modify function.
[01:50] In this case, the function we're going to apply is this dec function. It takes a number to number and just subtracts one from our input, returning the result. After a quick save, we'll take this for a spin by importing it into our index file by referencing decLeft from our file, which we pull from the path data model answer, from which it was exported from.
[02:15] With another quick save, we take a stroll downstairs and log out a call to decLeft, calling it with unit. We see we get back a state instance. We run the instance with execWith, passing it our initial state. We see that left has indeed been decremented.
[02:30] We can chain in another call to decLeft to decrement again. Because of our clamps -- insert "Futurama" reference -- we can chain so much and never go below zero. We can even start at a zero state and be assured that we'll only have the values within the range we desire, no matter how it's called.
[02:49] With decLeft in the bag, we'll reset our initial state and do something similar for our moves attribute, so similar in fact that we'll copypasta decLeft and then update the name, the function used with limitMoves, and the key we want to modify.
[03:04] We rename it to incMoves in both the signature and the actual function name. Change left to moves. Finally, replace dec with inc. In order to test this, in our index file, we swap out decLeft with incMoves in our import statement, as well as down below in our logging function, and observe our moves being incremented.
[03:27] Just like decLeft, we can chain incMoves and get the expected behavior for one chain or by chaining as many as we want without any worry about these values stepping outside of our desired limits.