Subscribe on changes!

Functional Ref

avatar
Sep 13th 2021

What problem does this feature solve?

We all know it's somewhat annoying to use .value everywhere with refs, which is the motivation behind ref-transform as I understand it. The problem with a compiler solution is it makes what's actually going on less clear to the developer, not more clear. I would like to propose an alternative functional syntax that feels cleaner to me than the current ref but doesn't obfuscate the internals.

What does the proposed API look like?

The API is pretty straightforward. It would add another reactive factory (call it fRef for now), with the accompanying shallowFRef. Instead of a class with a value getter and setter, it would return a function with a .set property. Something like this:

import { defineComponent, fRef } from 'vue';

export const Counter = defineComponent({
  setup() {
    const counter = fRef(0);

    const increment = () => {
      counter.set(counter() + 1);
    };

    return () => (
      <>
        <div class="counter">{ counter() }</div>
        <button onClick={increment}>Increment</button>
      </>
    );
  }
});

I think this could be particularly useful for two-way binding:

import { defineComponent, fRef } from 'vue';

export const Counter = defineComponent({
  setup() {
    const myValue = fRef('Default value');

    return () => (
      <MyField modelValue={myValue()} onUpdate:modelValue={myValue.set} />
    );
  }
});

In my opinion, this makes it eminently clear that the fRef is not just a simple variable, which is helpful to the developer, but is easier to work with than the current ref. Of course, this can be implemented for computed as well (where the readonly computed variant does not have a .set method).

avatar
Sep 13th 2021

This should be commented in the composition api RFC but given the state of it and this not bringing anything beyond another way of doing things, I doubt it will make sense to add it. If you still want to discuss it, do it through the rfcs repo.