Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Steady State With Ember Octane

Jessy Jordan
September 16, 2019

Steady State With Ember Octane

Ever wondered where your component state went or where it came from? In this talk you will learn how arguments, decorators and tracked properties make state management of your component built in Ember Octane easier than ever before. In comparison with patterns known from traditional Ember apps, you will learn how to transform your modern components to predictable and future-proof building blocks of your application.

Jessy Jordan

September 16, 2019
Tweet

More Decks by Jessy Jordan

Other Decks in Programming

Transcript

  1. 2 JESSICA JORDAN simplabs Ember Learning Core Team Editor at

    Weekly Newsletter The Ember Times EmberJS Berlin Organizer Senior Frontend Engineer at @jjordan_dev
  2. A program is described as stateful if it is designed

    to remember preceding events or user interactions; […] the remembered information is called the state of the system. What is state? A Definition @jjordan_dev
  3. 0 1 State in JavaScript apps is constantly changing USER

    INTERACTIONS EVENTS INCOMING NETWORK REQUESTS @jjordan_dev
  4. 1 Types of State in JavaScript apps LOCAL STATE CLOSURE

    STATE OBJECT STATE GLOBAL STATE @jjordan_dev
  5. 1 Types of State in JavaScript apps LOCAL STATE CLOSURE

    STATE OBJECT STATE GLOBAL STATE @jjordan_dev
  6. State Management in Ember apps is about Object State SERVICE

    STATE CONTROLLER STATE COMPONENT STATE
  7. Managing Ember Component State PROPERTIES ARGUMENTS LIFECYCLE HOOKS EVENT HANDLING

    DEPENDENCY INJECTIONS DATA LOADING COMPONENTS OWN STATE AND METHODS TO MANIPULATE LOCAL AND EXTERNAL STATE
  8. 27 Symptoms of Component State That Is Hard to Manage

    Cyclical data flows Race conditions Overall unpredictable behaviour Low performance @jjordan_dev
  9. 1 When it’s not always clear where a property was

    set 1 {{#if hasPacked}} 2 <h2>Inventory</h2> 3 <ul> 4 {{#each inventory as |item|}} 5 <li>{{item}}</li> 6 {{/each}} 7 </ul> 8 {{else}} 9 No one packed anything... 10 {{/if}} @jjordan_dev
  10. When it’s not always clear where a property was set

    1 import Route from '@ember/routing/route'; 2 3 export default Route.extend({ 4 model() { 5 return ['Tent', 'Water Bottle','Frisbee', ‘Cookies']; 6 } 7 }); @jjordan_dev
  11. When it’s not always clear where a property was set

    1 {{ember-fest inventory=model}} @jjordan_dev 1 import Route from '@ember/routing/route'; 2 3 export default Route.extend({ 4 model() { 5 return ['Tent', 'Water Bottle','Frisbee', ‘Cookies']; 6 } 7 });
  12. 1 When it’s not always clear where a property was

    set 1 {{ember-fest inventory=model}} Inventory Tent Water Bottle Frisbee Cookies @jjordan_dev
  13. When it’s not always clear where a property was set

    1 {{ember-fest inventory=model}} @jjordan_dev 1 import Route from '@ember/routing/route'; 2 3 export default Route.extend({ 4 model() { 5 return ['Tent', 'Water Bottle','Frisbee', ‘Cookies']; 6 } 7 });
  14. ? When it’s not always clear where a property was

    set 1 {{ember-fest}} @jjordan_dev
  15. ? When it’s not always clear where a property was

    set 1 {{#if hasPacked}} 2 <h2>Inventory</h2> 3 <ul> 4 {{#each inventory as |item|}} 5 <li>{{item}}</li> 6 {{/each}} 7 </ul> 8 {{else}} 9 No one packed anything... 10 {{/if}} @jjordan_dev
  16. ? When it’s not always clear where a property was

    set 1 {{#if hasPacked}} 2 <h2>Inventory</h2> 3 <ul> 4 {{#each inventory as |item|}} 5 <li>{{item}}</li> 6 {{/each}} 7 </ul> 8 {{else}} 9 No one packed anything... 10 {{/if}} @jjordan_dev
  17. 1 When it’s not always clear where a property was

    set 1 {{ember-fest}} Inventory keys wallet phone @jjordan_dev
  18. 1 When it’s not always clear where a property was

    set 1 {{ember-fest}} Inventory keys wallet phone @jjordan_dev
  19. When it’s not always clear where a property was set

    1 import Component from '@ember/component'; 2 import computed from 'ember/object'; 3 4 export default Component.extend({ 5 hasPacked: computed.notEmpty('inventory'), 6 inventory: computed(function() { 7 return ['keys', 'wallet', 'phone']; 8 }, 9 }); @jjordan_dev
  20. When it’s not always clear where a property was set

    1 import Component from '@ember/component'; 2 import computed from 'ember/object'; 3 4 export default Component.extend({ 5 hasPacked: computed.notEmpty('inventory'), 6 inventory: computed(function() { 7 return ['keys', 'wallet', 'phone']; 8 }, 9 }); @jjordan_dev
  21. Data Ownership: “Is it an argument or not?” 1 {{#if

    hasPacked}} 2 <h2>Inventory</h2> 3 <ul> 4 {{#each inventory as |item|}} 5 <li>{{item}}</li> 6 {{/each}} 7 </ul> 8 {{else}} 9 No one packed anything... 10 {{/if}} @jjordan_dev
  22. Data Ownership: “Is it an argument or not?” 1 {{#if

    hasPacked}} 2 <h2>Inventory</h2> 3 <ul> 4 {{#each @inventory as |item|}} 5 <li>{{item}}</li> 6 {{/each}} 7 </ul> 8 {{else}} 9 No one packed anything... 10 {{/if}} @jjordan_dev
  23. Data Ownership: “Is it an argument or not?” 1 {{#if

    this.hasPacked}} 2 <h2>Inventory</h2> 3 <ul> 4 {{#each @inventory as |item|}} 5 <li>{{item}}</li> 6 {{/each}} 7 </ul> 8 {{else}} 9 No one packed anything... 10 {{/if}} @jjordan_dev
  24. Data Ownership: “Is it an argument or not?” 1 import

    Component from '@glimmer/component'; 2 3 export default class EmberFest extends Component { 4 get hasInventory() { 5 return this.args && this.args.inventory; 6 } 7 } @jjordan_dev
  25. Data Ownership: “Is it an argument or not?” 1 import

    Component from '@glimmer/component'; 2 3 export default class EmberFest extends Component { 4 defaultInventory = ['Rain Coat', 'Blanket']; 5 6 get hasInventory() { 7 return Boolean(this.internalInventory); 8 } 9 10 get internalInventory() { 11 return this.args.inventory || 12 this.defaultInventory; 13 } 14 } @jjordan_dev
  26. @jjordan_dev Presentation of Data Holding & Loading of Data Methods

    for Modifying Owned Data Data Management vs. Data Presentation
  27. A B Enforced DDAU with Argument Immutability “PARENT” = CONTROLLER,

    DATA OWNING COMPONENT “CHILD” = PRESENTATIONAL OR INTERMEDIARY COMPONENT @jjordan_dev
  28. A B Enforced DDAU with Argument Immutability PASS DOWN ARGUMENTS

    AND ACTIONS SEND UPDATED VALUES UP VIA ACTIONS @jjordan_dev
  29. 1 import Component from '@glimmer/component'; 2 import { action }

    from '@ember/object'; 3 4 export default class EmberFest extends Component { 5 // ... 6 @action 7 changeItem(item) { 8 this.args.updateItem(item); 9 } 10 } B @jjordan_dev No Ambiguity About Property Updates
  30. B 1 <h2>Inventory</h2> 2 <p>Choosing {{@chosenItem}}</p> 3 <ul> 4 {{#each

    @inventory as |item|}} 5 <li> 6 {{item}} 7 <button 8 {{on "click" (fn this.changeItem item)}}> 9 Choose {{item}} 10 </button> 11 </li> 12 {{/each}} 13 </ul> @jjordan_dev No Ambiguity About Property Updates
  31. A C SERVICE INJECTION SERVICE: OWNER OF APPLICATION STATE B

    D TARGET INSTANCE, E.G. COMPONENT, CONTROLLER, SERVICE @jjordan_dev Modifying Application Wide State with Components
  32. A C SERVICE INJECTION SERVICE: OWNER OF APPLICATION STATE B

    D TARGET INSTANCE, E.G. COMPONENT, CONTROLLER, SERVICE UPDATING VALUES DIRECTLY OR VIA HELPER METHODS @jjordan_dev Modifying Application Wide State with Components
  33. 1 import Service from '@ember/service'; 2 import { tracked }

    from '@glimmer/tracking'; 3 import moment from 'moment'; 4 5 export default class TimeService extends Service { 6 @tracked currentTime = moment().format('MM/DD/YYYY HH:mm'); 7 8 resetTime() { 9 this.currentTime = moment('2019-09-16 09:00’) 10 .format(‘MM/DD/YYYY HH:mm'); 11 } 12 } @jjordan_dev Modifying Application Wide State with Components
  34. 1 import Component from '@glimmer/component'; 2 import { action }

    from '@ember/object'; 3 import { inject as service } from '@ember/service'; 4 5 export default class EmberFest extends Component { 6 @service time; 7 // ... 8 @action 9 resetTime() { 10 this.time.resetTime(); 11 } 12 } @jjordan_dev Modifying Application Wide State with Components
  35. Encouraged DDAU Facilitates State Management 72 ENCOURAGES DIRECTED ACYCLICAL GRAPHS

    (DAG) FOR DATA FLOW EASIER SEPARATION OF CONCERNS PREVENTS ACCIDENTAL OVERWRITES OF COMPUTED PROPERTIES @jjordan_dev
  36. - 11 LIFECYCLE HOOKS - 29 EVENT HANDLERS + 1

    CONSTRUCTOR SINGLE LOCATION OF HOOKS A LEANER API WITH GLIMMER COMPONENTS @jjordan_dev
  37. 77 Performance Wins for Your Components in Ember Octane Use

    Template Only Components Facilitate Garbage Collection with Local State Avoiding repeated rendering @jjordan_dev
  38. 79 Performance Wins for Your Components in Ember Octane @jjordan_dev

    Use Template Only Components Facilitate Garbage Collection with Local State Avoiding repeated rendering
  39. 81 Performance Wins for Your Components in Ember Octane @jjordan_dev

    Use Template Only Components Facilitate Garbage Collection with Local State Avoiding repeated rendering
  40. Managing Component State with Ember Octane Clear Data Ownership with

    Named Arguments Encouragement of DDAU for Improved Separation of Concerns @jjordan_dev
  41. Modify Application Wide State via Services Prevention against Accidental Computed

    Property Overwrites Intuitive Event Handling with Lean Component API 84 @jjordan_dev
  42. Experience the Future of Steady State with Ember Octane Performance

    Boost with New Octane Features and Smart Local State Management 85 @jjordan_dev