MacroMeals

A delectable demo of Signals by Kristen Hewell Garrett (@pzuraq)

Quick sensitivity warning

The example app in this demo is for planning meals around

high level macro nutrient goals. It's not an app for tracking food

consumption or calories, but is conceptually related to those types of apps.

Core Problem: Meal Planning is hard!

  • Different individuals have different goals for macros
    (e.g. amount of protein, carbs, fats, etc. per day/week)
  • Don't want to have completely separate plans
    (that's n-times the cooking!)
  • Ideally, we could:
    • Make a basic meal plan to start
    • Change each individuals servings per-meal
    • Add on extras or change meals out for each person
    • Tweak recipes and see how that affects the big picture

How do we model this with Signals?

const cheese = new Signal.State({
  name: 'Cheese!',
  servingSize: 1,
  servingMeasure: 'cups',
  protein: 4,
  carbs: 5,
  fat: 7,  
});
const quesadilla = new Signal.State({
  name: 'Quesadilla',
  ingredients: [
    {
      value: cheese,
      amount: 0.5
    },
    {
      value: tortilla,
      amount: 1,
    }
  ]
});
const quesMacros = new Signal.Computed(() => {
  const macros = {
    protein: 0,
    carbs: 0,
    fats: 0,
  };
  
  const { ingredients } = quesadilla.get();

  for (const { value, amount } of ingredients) {
    const {
      protein,
      carbs,
      fat,
    } = value.get();

    macros.protein += protein * amount;
    macros.carbs += carbs * amount;
    macros.fats += fat * amount;
  }

  return macros;
});
const plan = new Signal.State({
  name: 'Friday',
  people: ['Kristen', 'Liz'],
  meals: [
    {
      name: 'Breakfast',
      items: {
        Kristen: [
          {
            value: quesMacros,
            amount: 2,
          },
          {
            value: cheese,
            amount: 1,
          }
        ],
        Liz: [
          {
            value: quesMacros,
            amount: 3,
          }
        ]
      }
    }
  ]
});
const planMacros = new Signal.Computed(() => {
  const { people, meals } = plan.get();

  const macros = {};

  // initialize each person
  for (const person of people) {
    macros[person] = {
      protein: 0,
      carbs: 0,
      fat: 0,
    }
  }

  // loop over each meal to get the items
  for (const { items } of meals) {
    // loop over people to get their specific 
    // items for that meal
    for (const person of people) {
      // loop over the items for that person
      for (const { value, amount } of items[person]) {
        // ok, finally add the item macros to the totals!
        const {
          protein,
          carbs,
          fat,
        } = value.get();

        macros[person].protein += protein * amount;
        macros[person].carbs += carbs * amount;
        macros[person].fat += fat * amount;
      }
    }
  }

  return macros;
});

How did Signals help?

  • Separated data and business logic from the view layer completely
  • Let us think about the data model independent of the view
  • Handled reactivity for us - no need to tell the view when something has updated!
  • No need to drill reactivity through dependencies.
    • If we update an Ingredient, the Recipe and Plan will automatically update, and so will their macros
    • View layer automatically receives these updates just by using Recipe and Plan - don't need to tell it explicitly that it depends on Ingredients as well

Q&A

Thank you!

@pzuraq | pzuraq.com