Skip to content

Instantly share code, notes, and snippets.

@timhall
Created November 28, 2018 22:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timhall/bae8d3e87e9967d30b03096e065f873c to your computer and use it in GitHub Desktop.
Save timhall/bae8d3e87e9967d30b03096e065f873c to your computer and use it in GitHub Desktop.

Reactive Declarations

To avoid issues with re-calculating immediately on change while keeping reactive values in-sync, use reactive accessors to implement pull-based reactive values.

// Initialized with <Component a=15 />

export let a = 10;
let b = 20;

assert.equal(a, 15);

let c, d;
reactive: c = a + 1;
reactive: {
  d = expensiveSum(a, b);
  console.log(d);
} // -> 16 (on initialize)

assert.equal(c, 16);

function handle_click() {
  a += 1;
  assert.equal(c, 17);

  b += 1;
  // -> 37
  assert.equal(d, 37);
}

Transforms roughly into:

function init($$self, $$initial_props, $$make_dirty, $$make_reactive) {
  const __recompute = { flags: 1 | 2 };
  const __dirty_a = () => { $$make_dirty('a'); __recompute.flags |= 1 | 2 };
  const __dirty_b = () => { $$make_dirty('b'); __recompute.flags |= 2; };
  const __dirty_c = () => { $$make_dirty('c'); };
  const __dirty_d = () => { $$make_dirty('d'); };

  let { a = 10 } = $$initial_props;
  let b = 20;

  assert.equal(a, 15);

  let c, d;
  const __r_0 = $$make_reactive(__recompute, 1, () => {
    c = a + 1;
    __dirty_c();
  }); __r_0();
  const __c = __r_0;

  const __r_1 = $$make_reactive(__recompute, 2, () => {
    d = expensiveSum(a, b);
    __dirty_d();
    console.log(d);
  }); __r_1();
  const __d = __r_1;

  __c();
  assert.equal(c, 16);
  __d();
  assert.equal(d, 35);

  function handle_click() {
    a += 1;
    __dirty_a();
    __c();
    assert.equal(c, 17);
    
    b += 1;
    __dirty_b();
    __d();
    assert.equal(d, 37);
  }

  $$self.get = () => {
    return { a, b, c, d, handle_click };
  };
  $$self.synchronize = () => {
    __r_0();
    __r_1();
  };
}

Where $$make_reactive is roughly:

function $$make_reactive(recompute, id, compute) {
  return () => {
    if (recompute.flag & id) {
      compute();
      recompute.flag ^= id;
    }
  };
}

The doubled-quadrupled example from RFC#8 would look like:

function init($$self, $$initial_props, $$make_dirty, $$make_reactive) {
  const __recompute = { flag: 1 | 2 };
  const __dirty_count = () => { $$make_dirty('count'); __recompute.flag |= 1; };
  const __dirty_doubled = () => { $$make_dirty('doubled'); __recompute.flag |= 2; };
  const __dirty_quadrupled = () => { $$make_dirty('quadrupled'); };
  
  let count = 1;
  let doubled;
  let quadrupled;

  const __r_0 = $$make_reactive(__recompute, 1, () => {
    doubled = count * 2;
    __dirty_doubled()
  }); __r_0();
  const __doubled = __r_0;
  
  const __r_1 = $$make_reactive(__recompute, 2, () => {
    quadrupled = doubled * 2;
    __dirty_quadrupled()
  }); __r_1();
  const __quadrupled = __r_1;

  function handle_click() {
    count += 1;
    __dirty_count();
  }

  $$self.get = () => {
    return { count, doubled, quadrupled, handle_click }
  };
  $$self.synchronize = () => {
    __r_0();
    __r_1();
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment