ES6 Proxy: set property trap with debounce, is it possible to avoid dictionary of callbacks?

355 Views Asked by At

Goal: get any changed form field as 'name-value' pair on user input with debounce while typing. Sample template (person is two-way binded model).

<form>
  <q-input v-model="person.familyName" />
  <q-input v-model="person.givenName" />
  ...
</form>

I got it to work with ES6 Proxy, but seems there is code smell with dictionary of debouncing callbacks: each property puts own callback to dictionary to not interfere with other fields.

// callback per 'field name' to prevent from skipping changes
// while fast typing with Tab button to switch between fields.
const debounces: { [key: string]: (...args: any[]) => any } = {};

const person = new Proxy(someSourceModel, {
    set: (target, key: string, value, receiver) => {
        Reflect.set(target, key, value, receiver);

        if (!debounces[key])
            debounces[key] = debounce(300, (key, value) => // throttle-debounce lib
            {
                // Do anything with changed key-value pair.
                // For example, send it with update to Dexie/PouchDB as
                // single field instead of whole object.
                console.log(`${String(key)}: ${String(value)}`);

                delete debounces[key]; // Cleanup when it fired.
            });

        debounces[key](key, value); // Fire it!
        return true;
    }
});

Is there any way to avoid dictionary of callbacks?

Codesandbox working example included.

1

There are 1 best solutions below

0
On

Possible solution with lodash-es/debounce: immediate call 'flush' of pending debounce when another property changed.

let lastProperty: string;

const onChanged = debounce((key, value) => {
    // Do anything with changed key-value pair.
    // For example, send it with update to Dexie/PouchDB.
    console.log(`${String(key)}: ${String(value)}`);
}, 300);

const person = new Proxy(someSourceModel, {
    set: (target, key: string, value, receiver) => {
        Reflect.set(target, key, value, receiver);

        if (lastProperty != key) {
            lastProperty = key;
            onChanged.flush();
        }

        onChanged(key, value);
        return true;
    }
});

Codesandbox example