2 3. Reactivity
~coolelectronics edited this page 2024-03-10 10:39:32 -04:00

Data Modeling / Reactivity

The reactivity system is extremely simple, but it can take some time to get to know it.

At a basic level, if you call use and pass in a property that belongs in a stateful context, it gives back a dynamic reference that will update automatically as the data updates.

The value of this inside a functional component is always stateful, letting this example from earlier work

function App() {
  this.counter = 0;
  return (
    <div>
      <button on:click={() => this.counter++}>Click me!</button>
      <p>
       {use(this.counter)}
      </p>
    </div>
  );
}

Whenever counter is updated, either from inside the component, from a parent component, or from devtools, the specific elements that depend on the value precisely update to reflect the new value with minimal overhead.

You can also manually create a stateful object, which is useful for nesting.

let state = stateful({
    a: 0,
    b: stateful({
        c: 1
    })
})

let elm = <div> a is {use(state.a)}, c is {use(state.b.c)}</div>
document.body.appendChild(elm);

state.a++
state.b.c++
// div will now show "a is 1, c is 2"

Mapping

It's important to remember that use yields a reference pointer, not the actual value. As such, something like this will not work

<div>
    <button on:click={() => this.counter++}>Click me!</button>
    {use(this.counter % 2 == 0 ? "Count Is Even" : "Count Is Odd")}
</div>

As the function is only executed once ever. To have additional logic tied to state changes, you can pass in a closure to the second argument of use.

<div>
    <button on:click={() => this.counter++}>Click me!</button>
    {use(this.counter, count => count % 2 == 0 ? "Count Is Even" : "Count Is Odd")}
</div>

This will have the expected behavior, flipping between even and odd when the button is pressed. Remember that the "count % 2 == 0" operation is recalculated every time count changes, but nothing else in the function is rerun.