Autor Zpráva
weroro
Profil
Zdravím,
snažím sa o vytvorenie akejsi reaktívnej triedy za pomoci Proxy.
Narazil som však na problém, ktorý nedokážem vyriešiť a ani vygoogliť.

Moja myšlienka je na dnešnú dobu prostá. Vedieť sledovať stav fieldov v inštancii nejakej mojej triedy. Podobne ako to má Angular, že ak v rámci triedy zmením nejakú premennú, tak sa vykoná nejaká akcia.

Momentálny funkčný stav, avšak nie pre mňa uspokojivý je tento:
class ProxyTest {
    constructor() {

        Object.setPrototypeOf(this, new Proxy(Object.create(this.constructor.prototype), {
                set: (target, property, value) => {
                    console.log('proxy:', value);
                    target[property] = value;
                    return true;
                },
            })
        )

        this.web = 'DJPW';
        setTimeout(() => {
            this.web = 'Jak psát web';
        }, 2000);
    }
}

const proxyTest = new ProxyTest();
Po vytvorení inštancie triedy sa pripojí Proxy [console.log vypíše "proxy: DJPW"] a sleduje zmeny všetkých fieldov konštruktoru. Po 2 sekundách, sa zmení hodnota sledovaného fieldu (simulácia nejakej asynchrónnej akcie - napr. fetch) a zareaguje mi na túto zmenu Proxy [console.log vypíše "proxy: Jak psát web"] .

Ja však potrebujem presunúť zadefinovanie Proxy mimo konštruktor, dokonca mimo triedu úplne.
Moja predstava je v zmysle:
class ProxyTest {
    constructor() {
        this.web = 'DJPW';
        setTimeout(() => {
            this.web = 'Jak psát web';
        }, 2000);
    }
}

const proxyTest = new ProxyTest();

Object.setPrototypeOf(proxyTest, new Proxy(Object.create(proxyTest.constructor.prototype), {
                set: (target, property, value) => {
                    console.log('proxy:', value);
                    target[property] = value;
                    return true;
                },
            })
        )

A tu som narazil na problém, že neviem ako to dosiahnuť. Nahradením this za inštanciu proxyTest sa nič nevyriešilo a je to bez reakcie.

Mohli by ste mi prosím poradiť, prípadne mi dať iné riešnie pre dosiahnutie môjho cieľa? Ďakujem za váš čas.
Radek9
Profil
weroro:
Problém je, že v tom druhém případě ten handler nastavuješ až ve chvíli, kdy už ta property web existuje přímo na tom objektu proxyTest. V tu chvíli na její změny ta proxy schovaná v prototypu nereaguje. Takže musíš nejdřív tu property smazat, potom nahradit prototyp a teprve potom ji tam znovu přidat, aby se propsala do té proxy:
const proxyTest = new ProxyTest()
let web = proxyTest.web
delete proxyTest.web
Object.setPrototypeOf(
  proxyTest,
  new Proxy(Object.create(proxyTest.constructor.prototype), {
    set: (target, property, value) => {
      console.log('proxy:', value);
      target[property] = value;
      return true;
    },
  })
)
proxyTest.web = web

Obecněji pro všechny properties by se to dalo napsat takhle:
const proxyTest = new ProxyTest()

let props = Object.entries(proxyTest)
for (let [key] of props) {
  delete proxyTest[key]
}

Object.setPrototypeOf(
  proxyTest,
  new Proxy(Object.create(proxyTest.constructor.prototype), {
    set: (target, property, value) => {
      console.log('proxy:', value);
      target[property] = value;
      return true;
    },
  })
)

for (let [key, val] of props) {
  proxyTest[key] = val
}
weroro
Profil
Radek9:
Vynikajúce. Veľmi pekne ti ďakujem. Aj za vysvetlenie. Ja som experimentoval s podobným riešením ako si dal ty, ale neúspešne. Teraz už viem prečo. Ja som totiž nezmazal originálne properties, tak som bol v tom, že sa jedná o nefunkčný postup.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0