En er zijn nog steeds impliciet observers op die data aanwezig, ook al schrijf je ze zelf in een action.
Redux zal toch echt iets moeten registreren om te weten wanneer die actie aangeroepen moet worden.
En React zelf zal toch echt op de één of andere manier ook een schop moeten krijgen om de view bij te gaan werken.
En waar bestaat volgens jou een 'observer' uit?
CanJS maakt bijv. gebruik van een structuur waar observables werken als een soort van event source die op een gegeven moment een 'change' event naar buiten stuurt, tenminste:
als er iets actief naar aan het luisteren is. Is dat niet het geval, dan worden die events niet gevuurt. (Dat werkt overigens transitief: computed properties die niet geobserveerd worden, observeren hun dependents ook niet.)
Je trekt heel hard aan het feit dat er altijd observers actief zijn en dat het maken van al die observers veel geheugen vreet. En dat is een veel te algemene stelling.
Nee. We hadden het over two-way vs one-way binding. Dat strekt verder dan enkel state management.
Maar goed; zelfs als we het enkel over state management zouden hebben, dan is het nog steeds on topic.
De genoemde technieken zorgen er namelijk voor dat de hoeveelheid bindings die tegelijk actief hoeven zijn, gelimiteerd blijft. En zorgen er voor dat de hoeveelheid data die je tegelijkertijd in je state hebt zitten ook gelimiteerd kan blijven. (Lazy loaden/disposen.)
Werk je dan met een framework wat een beetje efficient omgaat met bindings op observables (zoals ik hierboven al uitgelegd heb, bijv.) dan helpen zulke technieken vanuit de consumerende views wel degelijk mee aan het efficient houden van je state management.
Ed Vertijsment schreef op woensdag 2 januari 2019 @ 13:50:
[...]
Het zou helemaal inefficiënt zijn als een framework automatisch alles gaat binden. "Explicit is better than impliciet" houd ik hier even aan. Aurelia stelt je in staat om zelf de binding (type) aan te geven waar nodig. Een compleet model binden (kan ook) vind ik riskant aangezien die nogal eens heel groot kunnen worden. En als je alleen 1 boolean daarvan wilt binden zit je al vrij snel met overhead.
Eens.
Ed Vertijsment schreef op woensdag 2 januari 2019 @ 13:50:
In een goede listview implementatie doe je natuurlijk netjes aan garbage collection. Ik zeg overigens ook niet dat het onmogelijk is het goed te krijgen. Het is alleen veel makkelijker je zelf in de voet te schieten met two-way binding.
Maar, daar ben ik het oneens mee. Leg me eens uit waarom two-way data binding hier problemen zou leveren die je met one-way binding niet hebt?
Ed Vertijsment schreef op woensdag 2 januari 2019 @ 13:50:
Aurelia gebruikt ES6 classes waarvan getters geen normale properties zijn en niet goed observable zijn op bepaalde browsers (volgens mij was dit het dirty check scenario), die design choice kun in twijfel trekken, ik houd er zelf ook niet van. Ik vraag mij af hoe CanJS die observed en of dit in Aurelia inmiddels anders wordt gedaan.
CanJS trapt bewust niet in die valstrik en hanteert een eigen set observeerbare model classes. DefineMap voor objecten en DefineList voor arrays. Je schrijft property definitie specificaties per model eigenschap en het prototype van de class swapt die on-the-fly uit voor getter/setters die alle nodige hooks voor observability aan boord hebben.
Daarnaast werken ze aan een alternatieve observeerbare structuur dmv ES6 proxies.
Je hebt als ontwikkelaar daar de keuze wat je gaat doen.
Wil je liever een object van buiten het framework op een andere manier observeren, dan kun je daarvoor een eigen computed property definiëren met get/set/on/off functies om de waarde op te vragen; weg te schrijven; object-specifieke observatie handlers te registeren; en weer te ont-registreren.
Of (ongedocumenteerd, helaas) je maakt gebruik van het lager gelegen systeem waarmee CanJS bijv. Promise observeerbaar heeft gemaakt. Dat is ook niet echt moeilijk. De ontwikkelaars van dit framework hebben wat dat betreft heel goed naar extensibility gekeken.
Mja;
I calls 'em, as I sees 'em.
Als je nagaat dat elke keer wanneer iemand vraagt "waarom kan Aurelia dit niet?" hetzelfde excuus van stal gehaald wordt, om maar te vermijden te gaan kijken naar een rewrite. Ja; dan vind ik dat slap gezeik.
Ed Vertijsment schreef op woensdag 2 januari 2019 @ 13:50:
Je zou prima je
redux state in een worker thread kunnen draaien hoor, losse mutaties (actions) zijn namelijk een stuk makkelijk naar worker threads te communiceren.
Los daarvan heeft JS al standaard more or less zijn eigen queue, of je daar je state op wilt baseren is discutabel (Aurelia implementeert ook een custom queue) maar in essentie kan je door alles in een setTimeout() te wrappen code aan het einde van even loop douwen die gewoon FIFO wordt afgehandeld.
Grappig dat je met redux worker aankomt. CanJS had nl. 4 jaar geleden een experimentele branch waarmee ze je hele applicatie in een worker kunnen draaien en enkel de view nog op de main thread. Jammer genoeg nooit uitontwikkeld. Was een mooi concept; maar helaas lag de ontwikkelaandacht destijd elders.
CanJS' queue systeem werkt een klein beetje anders dan een naive setTimeout.
Ze maken feitelijk gebruik van een set van verschillende queues die in de juiste volgorde geflushed worden en - bijv. vanwege dependents in computed properties - weer aangevuld worden. Zo pingelen ze een paar keer heen en weer terwijl alles opnieuw uitgerekend wordt en state bijgewerkt wordt, alvorens de laatste queue gedraint wordt waar de DOM mutaties aan vast hangen om de view bij te gaan werken.
Klopt. Alles heeft z'n voors en z'n tegens.
Net zoals one-way binding niet impliciet beter/makkelijker/veiliger/sneller/etc dan two-way binding hoeft te zijn.
Dat is eigenlijk de boodschap hier.