--- tags: mstu5013, tutorial, js, riot --- :::warning **CORRECTION:** Note that I erroneously explained that riot has an internal/default `this.remove()` function. This is false. There is no `remove()` function available in Riot by default. (You can create one though.) The correct function that does this is `this.unmount()` I have corrected all instances of this to reflect the correct function. ::: # RIOT Tutorial 05: LIFECYCLE With Riot, we've been thinking about components/tags from a developer point of view as a process of: 1. Defining components/tags (`.tag` files) 2. Compiling them into JS 3. Instantiating them (turning them into _live_ JS objects) 4. And rendering them on the page (e.g. making them visible) DEFINE: We define the tag. ```jsx <my-tag> <p>Hi { username }</p> <button onclick={ sayHello }>Hello</button> <script> this.username = "jmk2142"; console.log("I am born."); sayHello(e) { alert('Hi!'); } </script> </my-tag> ``` COMPILE: Tag is compiled into JS definition _automatically_ if using `riot+compiler`. ```javascript riot.tag2('my-tag', '<p>Hi {username}</p> <button onclick="{sayHello}">Hello</button>', '', '', function(opts) { this.username = "jmk2142"; console.log("I am born."); this.sayHello = function(e) { alert('Hi!'); }.bind(this) }); ``` INSTANTIATE: A `new` instance is created of the tag `object` through the `riot.mount()` ![](https://i.imgur.com/JkdXtRm.png) RENDER: Tag is attached to DOM at `<my-tag></my-tag>` location and rendered. ```htmlmixed <html> ... <body> <my-tag></my-tag> ... </body> <script> riot.mount('my-tag'); </script> </html> ``` ![](https://i.imgur.com/qKpAXkh.png) We think of this as a process. And in this tutorial, we'll go deeper into the process of how our defined components become a part of the DOM and update themselves based on changes to our _STATE_ changes. ## Lifecycle STAGES: Key Points In RIOT, the tag's lifecycle is composed of various stages that are sequenced in time, and therefore, part of a continuum. 1. **MOUNT** - E.g. When as seen in `inspector ELEMENTS` a tag is attached to the DOM. 2. **UPDATE** - E.g. When the tag refreshes, like through an `{ interpolation }` change. 3. **UNMOUNT** - E.g. When as seen in `inspector ELEMENTS` a tag is removed from the DOM, like when using the `if={}` attribute that resolves to false. To use an analogy, tags are like living organisms. They are born (mounted), change (updated), and die (unmounted.) ### MOUNT: I am born As stated in the Riot Guides: See http://riotjs.com/guide/#tag-lifecycle > A tag is created in the following sequence: 1. Tag is constructed: - tag object is instantiated from `.tag` definition 2. Tag's JS logic is executed - code defined in `<script>` part of tag definition runs 3. HTML expressions are calculated: - code in `{ expression }` in template is evaluated 4. Tag is mounted on the page: - `<component>` is attached to the DOM Before the `mount`, a tag is not live. In order to interact with a tag, change it, etc. It must be mounted to the DOM. ```jsx <html> ... <my-tag></my-tag> // MOUNTING point/location ... <script> // Tells riot to instantiate a new Object, `my-tag` component // and mount it at the mounting point above. riot.mount('my-tag'); </script> </html> ``` Once we `mount` them, the tag is attached to the DOM and visible to the user. That means that the user or our program's internal logic can now interact with the content of the tag. ### UPDATE: I can change Our next stage in the lifecycle is the `update`. We've already seen this happen in our various examples and exercises. In RIOT, this happens automatically after an event handler (e.g. onclick, onchange, etc.) is called. ```jsx <my-tag> <p>Hi { username }</p> <button onclick={ sayHello }>Hello</button> // <-- 1. Button CLICKED <script> this.username = "jmk2142"; sayHello(e) { // <-- 2. Function CALLED this.username = "ab4464"; } // <-- 3. UPDATE occurs </script> </my-tag> ``` Riot provides a function called `update` which is called immediately, automatically after the execution of an event handler. You can also manually call `this.update()`, or suppress the default behavior through the event argument via inclusion of `e.preventUpdate = true;` inside our event handler function. We will discuss this further in the Lifecycle EVENTS section. Lastly, Riot will call `update` on all tags downstream of a parent. > Updates flow uni-directionally from parent to child. ```jsx <my-tag> <my-child> <my-grandchild></my-grandchild> </my-child> </my-tag> ``` In the above example, if `update` is called on `my-tag`, it will automatically call `update` on `my-child`, followed by an `update` on `my-grandchild`. Often times we utilize parent _state_ data in our children tags. Thus, it's common that any changes in _state_ at the upper levels will have an impact on lower levels - how child tags are rendered. Conversely, an `update` on a child _does not_ automatically call `update` on parent tags. ### UNMOUNT: Memento mori > Memento Mori: Remember that you have to die. The last stage of a tag lifecycle is the `UNMOUNT`. This is when the tag is completely removed from the DOM. It becomes inaccessible and the instance, including state data of that component will be wiped out. In _Chrome Inspector_ under _elements_ we've seen tags added, and removed from the DOM. Unmounting is the latter. We've seen something analogous in our examples as well. ```jsx <tweet-feed> <tweet if={ tweet.publish }></tweet> // Notice the IF attribute <button onclick={ trashTweet }>TRASH</button> <script> this.tweet = { publish: true }; trashTweet(e){ this.tweet.publish = false; } </script> </tweet-feed> ``` In the above example, when the button is clicked: 1. The `trashTweet` handler is called 2. The _state_ of `tweet.publish` is changed 3. The tag calls `update()` automatically, right-after However, since `tweet.publish` is now `false`, and the `<tweet>` component has the `if` attribute that evaluates to `false`, the `<tweet>` component will be removed or **unmounted** from the parent tag. Remember that `if` adds/removes elements, or if we're talking about components - **mounts/unmounts** components based on how the `if` attribute expression is resolved. If you don't want to _unmount_ a tag, but just want to hide it, use `show` or `hide`. In riot, you can _manually_ unmount a tag using the `this.unmount` function. ```jsx <tweet> <p>{ tweet.content }</p> <button onclick={ delete }>Remove Me</button> <script> this.tweet = { content: "I ate 50 pancakes." }; delete(e){ this.unmount(); // Manual UNMOUNT } </script> </tweet> ``` Each tweet will have a _Remove Me_ button that when clicked, will `this.unmount()` the tag itself. In other words, it will `unmount` itself, and wipe clean any associated data within it. This is a common pattern used in Riot applications. > Rest in peace, pancake tweet. :::info In the previous example, you could have also done this:<br><br> ```jsx <button onclick={ unmount }>Remove Me</button> ``` Since `this` is assumed in Riot templates, the `onclick` directly calls `this.unmount()` when the button is clicked. If that's all you want to do, this is a short-cut. However, this also underscores the importance of the Riot internal functions `update` and `unmount`. You should NOT use these names to define your own custom event handler functions. ::: ## Lifecycle EVENTS In the previous section, we discussed the major stages of a tag: `mount`, `update`, and `unmount`. **Why do we need to know about the lifecycle?** There are times when we want to do things immediately before or after each stage of the lifecycle. For example: - Maybe you want to _start_ getting data from a database right _after_ the tag `mount`. - Maybe you have data you want to convert right _before_ the tag `update`. - Maybe you want to send data about the tag _state_ to a database _before_ the `unmount`. In order to do this, throughout the app process we need a way to know: - The stage that a particular component is at. - A way to hook in our own custom routines at specific points in time around the stages. **Riot Lifecycle EVENTS allow you to listen for these particular moments.** Like other user interaction events we've worked with in the past (e.g. `click`, `change`, etc.) RIOT provides its own special events we can work with. As a tag is created, changed, removed - Riot can tell us things like the tag is just about to mount (Event: `before-mount`) or just completed the update and render (Event: `updated`) etc. Riot triggers these events automatically. Thus, we can listen for _specific_ lifecycle events - that is, for moments right _before and after each stage_, and assign event handler functions to execute when that event is triggered. Riot provides the following lifecycle events that are triggered immediately before, or after each major lifecycle stage: 1. `before-mount` triggered right before mounting the tag on the page. 2. `mount` triggered right after the tag is mounted on the page. 3. `update` triggered right before recalculation the _data/state_, before the update call. 4. `updated` triggered right after the tag and expressions were updated and rendered, after an update call. 5. `before-unmount` triggered right before removing the tag. 6. `unmount` triggered while completely removing the tag from the DOM. 7. `*` triggered with every single event. See [http://riotjs.com/guide/#listening-to-lifecycle-events](http://riotjs.com/guide/#listening-to-lifecycle-events) To listen for lifecycle events we can use following pattern: ```jsx this.on('eventName', function() { // handler code to execute }); ``` > `on` the `eventName`, run `function` Example with annotation: ```jsx // PATTERN: // this.on(event, callback) // Each time event is triggered, call the callback function. this.on('eventName', function(){ // handler code to be executed }) // VS. // Only once, call the callback function when event is triggered, // then stop listening. this.one('eventName', function(){ // handler code to be executed }) ``` `this.on()` is a function that creates a listener for `this` tag and assigns a handler. It has two parameters: `event` and `callback`. We have not used this method of creating event listeners and handlers yet. In the past, we simply used HTML/RIOT attributes like `onclick` to create the listeners and defined the handler functions elsewhere in our scripts. A more abbreviated pattern as follows: `this.on(event, callback)` - `event` represents the Riot lifecycle event we want to listen for. - Argument is a _String_ - Riot event names like: `before-mount`, `mount`, `update`, `updated`, `before-unmount`, `unmount`. - `callback` represents the hander function to execute when the event listener is triggered. - Argument is a _Function_ definition - We refer to this argument as a `callback`. Callbacks are executable code passed as an argument to a function. - `this.on()` will automatically call this function for us when `event` is triggered. :::info **Writing Callback Functions and Common Mistakes** The first time you see a structure like this: ```javascript this.on('update', function() { ... }); ``` it looks a bit confusing, especially where the functions start and end. Take a look at the following examples that show the same functionality, but are presented differently to show you the underlying structure of the code. --- SEPARATED to show `this.on` has only 2 parameters: ```javascript function doSomething() { // named function alert('Hello!'); } this.on('update', doSomething); ``` COMMON/STANDARD way to write: ```javascript this.on('update', function() { // anonymous function alert('Hello!'); }); // notice order of what the } closes and the ) closes. ``` EXAGERATED to show start/end of functions: ```javascript this.on('update', function() { alert('Hello!'); } // closes anonymous function ); // closes this.on function call ``` These are identical in functionality and shown to explicitly illustrate that we are passing in only _TWO_ arguments. Also, I wanted you to _carefully_ observe the closings of the `callback` and the `this.on` function call. --- **MANY PEOPLE MAKE MISTAKES BY NOT CLOSING PROPERLY.** Common mistakes and bad practices leading to errors: - Improperly indented code - Writing code top down instead of outside to inside - Missing `}` or `)` - Mixing the order of the closing `})` vs. `)}` Remember, you must close the `callback(){` function first `}`, then the `this.on(` function call `)`. ::: --- You probably have noticed these events being used in the Digital pet: ```jsx this.on('update', function() { var clone = this.opts.logs.slice(0); // Clone array this.logList = clone.reverse(); // Invert array (recent logs first) }); ``` In Digital Pet, there was an `info-console` component that took an array of log data from the parent. The array was ordered with the earliest logs at index `0` and latest logs at higher indices. However, there is a problem. If I loop from `0` on up, when I print the logs - the newest log messages will be printed at the bottom as I append new log items to the page. In the above code, I am basically reversing the order of the array so that the newest ones appear at the top of the page. Remember, every time the parent tag updates, so do children. So every time I add a new log to the log array of the parent, and pass that array to the child, I want to re-render the child component. Thus, right _BEFORE THE UPDATE_, _EVERY TIME_, I clone the original data, reverse it, set it to the _state_ property `logList` of this component, and then run `update` - refreshing the page, and showing the logs in the intended order with newest at top. Remember that `update` happens after every user event like `click`. Thus, our code -- the `callback` function above -- runs everytime the user interacts with the page (i.e. `feed`, `exercise`, `reset`.) In other words: `on` every `update` right-before, run the `function` to reorganize my data array. Listening to lifecycle events is a convenient way of hooking functions to changes happening in the tag lifecycle. Although we can take advantage of listening every single lifecycle, we will be using more frequently the `update` event. Learning about this particular event will become handy when working with databases. --- ### The `update` Event This section is for the `update` event, which is perhaps the most commonly triggered lifecycle event around which custom event hooks are created. :::info **Note on the term `UPDATE`** When we talk about `update` be careful in that we talk about it in several different contexts.<br><br> - Term `update` as a general lifecycle stage and concept. - Term `update` as an event that is triggered, that we can listen for and run a _callback_ function. - Careful -- `update` vs. `updated` events. - Term `update` as a function that is automatically called, i.e. `update()` to update and render the tag. <br> **Example of Sequence of different `update` contexts:**<br><br> 1. Tag enters `update` lifecycle stage after user `click`. 2. `update` event is triggered and associated handler _callback_ is executed. - Before `update()` function 3. `update()` function is called, rerenders/refreshes the page based on _states_. 4. `updated` event is triggered and associated handler _callback_ is executed. - After `update()` function ::: In RIOT we tend not to directly manipulate the DOM. RIOT does it automatically for us during the `update()` function call. This has implications for the User Interface. The `update` event is triggered right before the `update()` function is called, that rerenders/refreshes the page. Therefore, although we can't see it explicitly in our own code, there are things happening in the background. Example: ```jsx <user-profile> // UI for user's information <input placeholder="Enter username" ref="inputUsername"/> <label>About:</label> <textarea placeholder="Tell us about you!" ref="inputAbout"></textarea> // Event handler for saving user's information <button role="button" onclick={ saveUser }>SAVE</button> // User's Profile Section <div if={ user }> <h2>Welcome { user.username }!</h2> <p>{ user.about }</p> </div> <script> this.user; // Default state = undefined // 0. Button clicked (above) // 1. Function is called saveUser(e){ // 2. State is set this.user = { username: this.refs.inputUsername.value, about: this.refs.inputAbout.value }; } // 3. Update event triggered (no update listeners in this example) // 4. update() function called (refreshes page based on new state) </script> </user-profile> ``` In the example above: 1. User interacts with UI, user event is triggered and handler called. - From template: `onclick={ saveUser }` 2. State of `this.user` is set. - Data provided from user input 3. Immediately after the `saveUser()` function is called, Riot triggers the `update` event automatically. - If we were listening for the `update` event, the associated `callback` is executed. In example, we were not. 4. Riot then runs the `update()` function to rerender/refresh the page automatically. - I.e. We see the user profile ## Asynchronous Code: and `update` :::success **Synchronous vs. Asynchronous Execution** - As you may remember, in JS most execution of code happens **synchronously**. The program is executed line by line, top to bottom. It can't continue to the *next routine* until the *current routine* is completed. - In **asynchronous** code, code _starts_ synchronously but _takes a while to complete_. It doesn't wait for the _current routine_ to end before going on to the _next routine_. It proceeds through the rest of the _synchronous_ code line by line as expected. Whenever the _async_ routine is completed, code designated to happen after that completion, are executed. **Let's see an example:** Let's say you are doing some tasks: 1) paying bills, 2) laundry, 3) getting ready for a date. If you do the house chores **synchronously**, you will pay your bills (easy), do the laundry (takes a lot of time), and then prepare for your date (shower, etc.) By the time you finish the laundry, you will have no time left to get ready for the date. In this case, adopting an **asynchronous** execution for laundry will be more efficient since you can put the laundry in the washing machine, and in the meanwhile, get ready for your date. When the laundry is done, it will "buzz" signaling that you are ready to pick out your outfit and do whatever else you need to do. Meanwhile, the other date preparation is completed. ::: Have you ever visited a site and seen it load part of the page so you can get started, then as you worked, the other data being pulled from the network came through - rendering the rest of the page? How annoying would it be if _NOTHING_ loaded until the data transfer was complete? Unlike our code which happens one thing right after another, **synchronously** -- some code that we'll be dealing with take much much longer to complete. Conceptual Example: ```jsx initializePage(); // 0.001 ms to complete getTweetsFromDB(); // 10 sec to complete - slow connection to database update(); // ??? ``` _Synchronous_ code is code that executes one after another. So, we'd expect `initializePage()` to happen, followed immediately by `getTweetsFromDB()`, then `update()` to show the new set changes. This is how we've been coding so far. But imagine if we had to wait for `getTweetsFromDB()` to complete before we could move onto the `update()`. We'd be waiting 10 seconds. That's 10 seconds of a user seeing a blank page. The average attention span before people leave a page is 2 seconds. This will not work. And why **asynchronous** code matters. > **Asynchronous** programming is a **means** of parallel programming in which a unit of work runs separately from the main application thread and notifies the calling thread of its completion, failure or progress. In the example above, `getTweetsFromDB()` should be an _async_ operation, running in parallel while we immediately start execution of the next `update()`. At least we'll get a partially updated page with state changes that don't rely on the database. And when the _async_ operation completes -- that is, the data is returned from the DB, then we can update the page again to reflect those changes. Async code, is usually designed to run `callback` functions once the async operations are complete. Asynchronous Coneptual Example: ```jsx // 1. Sync - run function initializePage(); // 2. Sync - run function // 3. Async - Function running, sent request to DB, waiting for data... getTweetsFromDB(function() { // 5. Run this code when data has returned }); // 4. Sync - run function update(); ``` You'll notice a similar pattern used to the `callback` used in our listeners. This sort of async pattern is commonly used when we are dealing with things like databases, or timers, etc. ### How does this relate to `update()`? Remember that `update` only happens automatically after the handler to a user interaction event is called. Thus we are going to run into issues if we are not mindful of when async operations happen. Riot Example: ```jsx <feed> // For each tweet in tweets make a component. <tweet each={ item in tweets }></tweet> // 1. Button clicked <button onclick={ getTweets }>Get Tweets</button> // 0. Initial state of tweets this.tweets = []; // 2. Handler called getTweets(e) { getDataFromDB(); // 10 sec network call to database - async } // 3. update() immediately/automatically called... // ?. but what is the value of this.tweets? </feed> ``` In the above example, because the async function `getDataFromDB()` that actually receives data from the database takes 10 seconds, Riot's `update()` is called before our actual data from the database is available. Therefore, `this.tweets` is still an empty `[]` when the tag is updated. This means, we will see zero tweets. After 10 seconds, the data will come back from the database, but since `update()` was already called, the page will remain without tweets. What we want to do is manually call `update()` in the `callback` to our asynchronous function. That is, once the data is returned and the _state_ is updated, we manually trigger `update` and rerender the page. Riot + Async Example: ```jsx <feed> <tweet each={ item in tweets }></tweet> <button onclick={ getTweets }>Get Tweets</button> var that = this; this.tweets = []; // 1. Handler called getTweets(e) { getDataFromDB(function(dataFromDB) { // ASYNC -------------- that.tweets = dataFromDB; // 3. Data returned, set state that.update(); // 4. Manually update tag, new tweets shown }); } // 2. update() immediately/automatically called </feed> ``` We'll revisit this concept later when we talk specifically about databases. Keep in mind that `getDataFromDB()` is not a real function. It's something made up to conceptually get the poinst across. But we will see something very similar to this when we get to Firebase. For now, just keep in mind that in certain circumstances there will be a need to use asynchronous code and this has an impact on the default sequence of events that occur through RIOT. And to work around it, we will need to think about _state_, _sequence_, and _causality_ in order to properly update our tags. --- #### A Timer Example A timer has similar issues to the database example above. This phenomenon is a result of a discrepancy in the synchronicity with which the functions are being executed and the data retrieved. This becomes particularly evident when we use the `setTimeout` function, where we are explicitly delaying the execution of a function. For example, do `code` after `2 seconds`. ```jsx= <pet> <p>{ message }</p> <button onclick={ neutralize }>Bye Bye</button> // Set variable `that` to `this` tag var that = this; // Both reference this <pet> tag this.message = "Pet is happy."; this.health = 100; this.on('update', function() { if (this.health == 0){ this.message = "Pet is dead."; } }); neutralize(e){ // Real JS function that will execute code after time delay // arg1: callback // arg2: time in ms setTimeout(function(){ that.health = 0; }, 2000); } </pet> ``` In ORDER of operation: - **Line 17**: `neutralize()` is called after button click. - **Line 22 - 24**: Timer starts countdown. We use a `setTimeout()` function, we are simulating a database call that takes 2 seconds. - **Line 11 & 25**: Riot enters `update` stage, right after `neutralize()` is executed. However, `setTimeout()` is still counting down 2 seconds. `that.health` is still `100`. - **Line 11 - 15**: `update` event triggered, and heard. Evalation of `health` which is still `100` since countdown is not completed. `this.message` is therefore still `"Pet is happy."` - **Line 15**: Riot calls `update()` and page is refreshed. (Looks the same.) - **Line 23**: 2 seconds elapses, `callback` executes and `that.health` is set to `0`. No `update()` is called, _state_ is out of sync with page. We can correct this by adding the manual `update()` inside our async timer function as so. ```jsx setTimeout(function(){ that.health = 0; that.update(); // Manual update(), happens after 2 sec. }, 2000); ``` Now, when the tag hears the `update` event, the state will correctly be `0` and the `this.message` will be changed to the sad message. The tag will rerender itself and correctly display, being in sync with the _state_ of the tag. Again, you have to be keenly aware of the _sequence_, _state_, and _causality_ of things, especially when we get to asynchronous code. :::info **AUTHORS** By Anabel Bugallo and Jin Kuwata :::