2.4.2
https://jsfiddle.net/o7yvL2jd/
Ich habe nach dem richtigen Weg gesucht, HoC mit vue.js zu implementieren. Habe aber kein passendes Beispiel gefunden.
Der folgende Link enthält bekannte HoC-Implementierungen. Hat aber nicht funktioniert wie erwartet.
https://jsfiddle.net/o7yvL2jd/
Wie kann ich HoC mit vue.js implementieren?
Ich möchte nur wissen, wie man HoC auf die Weise von require.js implementiert.
Sie sind HoCs, die einfach als Parameter übergebene Komponenten rendern.
HoCs, die Slots und Events enthalten, werden normal gerendert.
Das zu rendernde Element fehlt oder die gerenderte Reihenfolge weicht von der baseComponent ab.
Einige HoC-Implementierungen funktionieren nicht mit Event-Handlern.
Hallo @eu81273
Vielen Dank für Ihr Interesse an diesem Projekt.
Bei Ihrem Problem handelt es sich jedoch um eine Nutzungs-/Supportfrage, und der Issue-Tracker ist ausschließlich für Fehlerberichte und Funktionsanfragen reserviert (wie in unserem Contributing Guide beschrieben).
Wir empfehlen Ihnen, im Forum , Stack Overflow oder in unserem Discord-Chat danach zu fragen, und helfen Ihnen gerne weiter.
FWIW, ich habe aus persönlichem Interesse nachgeschaut - das sollte in 100% der Fälle funktionieren.
const HOC = WrappedComponent => ({
props: typeof WrappedComponent === 'function' // accept both a construtor and an options object
? WrappedComponent.options.props
: WrappedComponent.props,
render (h) {
// reduce all slots to a single array again.
const slots = Object.keys(this.$slots).reduce((arr, key) => arr.concat(this.$slots[key]), []);
return h(WrappedComponent, {
attrs: this.$attrs,
props: this.$props,
on: this.$listeners,
}, slots);
}
});
Ich habe HOC04 in Ihrem Beispiel bearbeitet, da es der Lösung am nächsten kam:
https://jsfiddle.net/Linusborg/o7yvL2jd/22/
Bearbeiten: immer noch ein Problem mit Slots, Untersuchung ...
Ich könnte es gelöst haben: https://jsfiddle.net/BogdanL/ucpz8ph4/. Slots sind jetzt nur fest codiert, aber das ist trivial zu lösen.
Scheint, dass die Lösung entlang der Methode von @lbogdan liegt , aber createElement sollte eine Möglichkeit haben, Slots zu nehmen, genau wie es scopedSlots nehmen kann.
Allerdings ist es _noch_ viel Aufwand, ein HoC zu erstellen. Es gibt viel zu beachten, um durchzugehen, während Sie mit React nur die WrappedComponent mit Requisiten rendern.
Ich dachte nur an eine sehr einfache Lösung ... lassen Sie mich wissen, wenn ich hier etwas vermisse:
const HOC06 = WrappedComponent => Vue.extend({
mounted () {
console.log('mounted 6')
},
...WrappedComponent
})
Basierend auf den Beispielen von @LinusBorg und @lbogdan ist die minimalste HoC-Implementierung, die Komponenten mit Steckplätzen verarbeiten kann,:
const HoC = WrappedComponent => ({
props: typeof WrappedComponent === 'function'
? WrappedComponent.options.props
: WrappedComponent.props,
render (h) {
const slots = this.$slots;
const scopedSlots = {};
Object.keys(slots).map(key => (scopedSlots[key] = () => slots[key]));
return h(WrappedComponent, {
attrs: this.$attrs,
props: this.$props,
on: this.$listeners,
scopedSlots,
});
}
});
Wie @blocka erwähnt hat, ist es immer noch sehr aufwendig, ein HoC mit vue.js zu erstellen.
@eu81273
const HOC06 = WrappedComponent => Vue.extend({
mounted () {
console.log('mounted 6')
},
...WrappedComponent
})
Das scheint deinen Test zu bestehen, oder? Natürlich müssten Sie es anpassen, je nachdem, ob WrappedComponent ein Konstruktor oder ein Objekt ist, aber es müssen keine Slots, Ereignisse oder Props übergeben werden.
es ist immer noch viel Aufwand, ein HoC mit vue.js zu erstellen.
Abgesehen von dem Problem mit Slots liegt dies nur daran, dass Vue eine komplexere API als React hat, was in diesem Szenario ein Nachteil ist. Ich bewundere die minimale API von Reacts in solchen Anwendungsfällen – Vue wurde nur mit etwas anderen Gestaltungszielen entworfen, sodass HOCs nicht so einfach kommen wie in React.
Aber es sollte ziemlich trivial sein, eine createHOC()
-Hilfsfunktion zu erstellen, die diese anfängliche Einrichtung für Sie umschließt, nicht wahr?
Nun, es kommt wirklich darauf an, was das Endziel ist. Soweit ich weiß, besteht das Ziel von HoC darin, die ursprüngliche Komponente (WrappedComponent) irgendwie zu ändern (zu dekorieren), um Requisiten, Methoden, Ereignis-Listener usw. hinzuzufügen (oder einzufügen) (ähnlich wie ein Mixin, wirklich :smile: ). Die Variante HOC06
ändert nur die Komponentendefinition, sie ändert nicht die Art und Weise, wie sie instanziiert wird.
@blocka Das Ziel von HOCs ist es oft, den Zustand (z. B. von redux / vuex) abzurufen und ihn in die Requisiten der umschlossenen Komponente einzufügen - das würde mit Ihrem Ansatz nicht funktionieren.
@LinusBorg richtig. Ich wusste, dass es zu schön war, um wahr zu sein, und dass ich etwas Offensichtliches vergessen hatte.
Ich denke, dies ist ein gutes Beispiel für die Implementierung eines echten Anwendungsfalls HoC in Vue: https://github.com/ktsn/vuex-connect.
Vue Hocs wäre ein tolles Plus (da es fast immer in jeder Vue vs React-Debatte angesprochen wird). Vielleicht könnte ein offizielles Repo erstellt werden, um ein Vue-hoc-Creator-Paket zu entwickeln? Auf diese Weise konnten wir an einer robusten, unterstützten Implementierung arbeiten
Übrigens, ich habe einen besseren Weg gefunden: Verwenden Sie $createElement aus der übergeordneten Komponente anstelle der eigenen des HOC - dadurch löst das untergeordnete Element die Slots korrekt auf:
Süß, aber umso mehr Grund, dass es ein offizielles Tool geben sollte, also wir
nicht alle erfinden diesen Code immer wieder neu.
Am So, 30. Juli 2017 um 16:33 Uhr, Thorsten Lünborg [email protected]
schrieb:
Übrigens, ich habe einen besseren Weg: Verwenden Sie $createElement aus der übergeordneten Komponente
anstelle der eigenen des HOC - dies lässt das Kind die Slots richtig auflösen:https://jsfiddle.net/o7yvL2jd/23/
—
Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/vuejs/vue/issues/6201#issuecomment-318927628 , oder stumm
der Faden
https://github.com/notifications/unsubscribe-auth/AACoury4Fix2jsX_lyTsS6CYOiHJaOuVks5sTOiugaJpZM4Oh0Ij
.
Es tut mir leid, dass ich noch keine offizielle Lösung gefunden habe. Freut mich aber, dass du es süß findest.
Meine Lösung ist auch nicht perfekt, es gibt noch andere Probleme zu lösen - dh Scoped Slots funktionieren nicht mit meinem neuesten Trick.
edit: oh egal, sie funktionieren
Eine offizielle Lösung wird es wahrscheinlich geben, zumindest würde ich das erwarten - aber sie muss gründlich durchdacht und getestet werden.
Okay, also habe ich herumgespielt, um es einfacher zu machen.
Schau mal hier: https://jsfiddle.net/Linusborg/j3wyz4d6/
Ich bin mit der API nicht zufrieden, da es sich um eine sehr grobe Ideenskizze handelt, aber sie kann alles, was sie können sollte.
import { createHOC, createRenderFn, normalizeSlots } from 'vue-hoc'
const Component = {
props: ['message']
template: `<p>{{message}}</p>`
}
const HOC = createHOC(Component)
createHOC
kümmert sich um:
$createElement
mit dem vom übergeordneten Element aus, um die richtigen Slots aufzulösen.Das allein ist natürlich nicht sehr hilfreich. Der Spaß passiert also im zweiten Argument, das ein einfaches Komponentenobjekt ist.
Wenn Sie die Renderfunktion selbst schreiben möchten, können Sie dies natürlich tun. Wenn Sie nur Requisiten, Attrs oder Listener erweitern möchten, können Sie den createRenderFn
-Helfer verwenden. Es erstellt eine Renderfunktion wie die oben beschriebene Standardfunktion, führt jedoch alle attrs
, props
oder listeners
, die Sie ihm übergeben, mit denen des übergeordneten Elements zusammen.
const HOC = createHOC(Component, {
mounted() {
console.log(`lifecycle hooks work, it's simply component options`)
},
render: createRenderFn(Component, {
props: {
message: 'Hello from your HOC!'
}
}
})
Wenn Sie Ihre eigene Renderfunktion schreiben möchten, können Sie den Helfer normalizeSlots
verwenden, um das Objekt von this.$slots
in ein geeignetes Array zur Weitergabe umzuwandeln:
const HOC = createHOC(Component, {
render(h) {
return h(Component, {
props: { message: 'hi from HOC'}, // nothing from parent will be passed on
}, normalizeSlots(this.$slots))
}
})
Kommentare erwünscht :)
@LinusBorg Sehr schön!
Was meiner Meinung nach helfen würde, wäre, sich reale HoC-Anwendungsfälle auszudenken und sie mit diesen Primitives zu lösen.
Absolut.
Ich erwähne dieses Problem (EDIT (mybad): https://github.com/vuejs/vuejs.org/issues/658).
Da Sie die undokumentierte $createElement-API verwenden, wäre es sinnvoll, sie für Plugin-Entwickler zu dokumentieren.
Ihr Link ist falsch (es sei denn, Sie wollten wirklich auf eine Ausgabe von 2014 verlinken)
Aber ja, technisch gesehen fehlt die $ceateElement
API immer noch auf der API-Seite.
@AlexandreBonaventure Dieses Problem ist von vue 0.x Tagen. :Lächeln:
Außerdem ist createElement
hier dokumentiert: https://vuejs.org/v2/guide/render-function.html#createElement -Arguments .
Die Funktion ist als Argument der Render-Funktion dokumentiert, aber nicht, dass sie über this.$createElement
verfügbar ist. Dazu gibt es ein offenes Problem auf vuejs/vuejs.org/issues/658
@LinusBorg Aber es ist im Grunde dieselbe Funktion, die an die Funktion render()
gesendet wird, richtig?
genauso. Es ist nur nicht klar dokumentiert, dass es über diese Instanzmethode auch außerhalb der Renderfunktion verfügbar ist.
Ich spiele gerade mit dem obigen Beispiel und es gibt ein paar Probleme, wenn es in einem komplexeren Szenario verwendet wird, daher ist ein offizielles Repo erforderlich. Ein paar Anmerkungen:
withDefaultProps(withProps(component, {}), {})
, hat der zweite Hoc keinen Zugriff auf das Requisitenbeispiel des übergeordneten ElementsHey Leute, ich habe versucht, eine Implementierung davon zu schreiben.
https://github.com/jackmellis/vue-hoc/tree/develop
Lassen Sie mich wissen, was Sie denken, und ich werde versuchen, es bald zu veröffentlichen. Ich denke auch darüber nach, ein Paket im Recompose-Stil zu schreiben.
Ein Recompose-Style-Paket wäre toll. Hätte echt was gebrauchen können
wie kürzlich bei withState.
Am Samstag, den 19. August 2017 um 5:50 Uhr schrieb Jack [email protected] :
Hey Leute, ich habe versucht, eine Implementierung davon zu schreiben.
https://github.com/jackmellis/vue-hoc/tree/develop
Lassen Sie mich wissen, was Sie denken, und ich werde versuchen, es bald zu veröffentlichen. ich bin auch
Denken Sie darüber nach, ein Paket im Recompose-Stil zu schreiben.—
Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/vuejs/vue/issues/6201#issuecomment-323513287 , oder stumm
der Faden
https://github.com/notifications/unsubscribe-auth/AACoumQWQMgpVeIvzJ3Ti8A4kLBD04Hhks5sZq_zgaJpZM4Oh0Ij
.
@jackmellis Toll, dass du hier eine Führung übernimmst :)
Ein paar Gedanken zu Ihrem Feedback, das Sie zuvor gegeben haben:
Vue.config.optionsMergeStrategies
gemildert werden sollteAn die Namensgebung habe ich auch gedacht. Ich mag createRenderFn
nicht, etwas wie renderComponentWith
wäre aussagekräftiger und sinnvoller in einem Szenario, in dem wir es in einige andere Knoten einbetten:
render(h) {
return h('DIV', {staticClass: 'some-styling' }, renderComponentWith({ props: {... } }))
}
createHOC
ist also zuerst eine Komponente ohne Curry, und dann gibt es eine Curry-Variante createHOCc
. Das React-Ökosystem ist im Gegensatz zu Vue, das sich eher wie ein OOP-Framework verhält, sehr funktionsorientiert. Daher denke ich, dass es am besten ist, mit dem Rest von Vue konsistent zu bleiben, aber dennoch eine funktionale Alternative anzubieten.createRenderFn
, da es genau das tut. Aber je mehr ich das zusammenfasse, desto weniger denke ich, dass die Leute es direkt verwenden werden. Die allgemeine Verwendung wird etwa so sein:const hoc = createHOC(
Component,
{
created(){
/* ... */
}
},
{
props: (props) => ({
...props,
someProp: 'foo'
})
}
);
Vielleicht verstehe ich dein Beispiel nicht ganz?
Vielleicht verstehe ich dein Beispiel nicht ganz?
Nein, ich denke, Sie sind auf dem richtigen Weg, meine Gedanken gingen in eine ähnliche Richtung, als ich nach meiner letzten Antwort weiter darüber nachdachte.
In meinem ersten POC habe ich es eingefügt, damit die Leute zusätzliches Markup um die gerenderte Komponente hinzufügen können, aber das würde bedeuten, dass es nicht mehr wirklich ein HOC ist, da es auch die Benutzeroberfläche einbringen würde ...
Ja, ich denke, Sie versuchen, zusätzliche Inhalte zu rendern, Sie haben das HOC-Territorium verlassen und könnten genauso gut ein SFC erstellen, um damit umzugehen.
Ich habe gerade vue-hoc auf npm veröffentlicht!
Ich habe auch an vue-compose gearbeitet, was eine schnelle Dokumentationssitzung ist, die auch noch nicht fertig ist. Obwohl es der Neuzusammenstellung ähnlich ist, handhabt Vue viele clevere Dinge (wie Caching-Berechnungen und fördert die Verwendung von this
), sodass es eigentlich nicht ganz so komplexe (oder funktionale) Syntax benötigt.
extends
funktioniert anders, kann aber verwendet werden, um ähnliche Ergebnisse zu erzielen, das stimmt.
Ich werde dies schließen, da ich denke, dass das @jackmellis- Projekt eine solide Grundlage bietet. Wir beabsichtigen nicht, eine Möglichkeit zum Erstellen von HOCs in den Kern aufzunehmen, hauptsächlich weil wir keinen großen Vorteil gegenüber Mixins / Extends sehen.
hauptsächlich, weil wir keinen großen Vorteil gegenüber Mixins / Extends sehen.
@LinusBorg React hat mixin
bereits aufgegeben, HOC bringt viele Vorteile.
Dieser Artikel hat die Vorteile analysiert:
Ich denke, das Vue-Team sollte erwägen, HoC sorgfältiger zu unterstützen ... obwohl es nicht einfach ist (es scheint, dass Vue nicht auf diese Weise konzipiert ist).
Ich bin nicht davon überzeugt, dass HoCs ein so überlegenes Konzept sind. Die potenziellen Konflikte des „impliziten Vertrags“ können beispielsweise auch bei HoCs auftreten.
Siehe dazu diesen Vortrag des Betreuers von React-router: https://www.youtube.com/watch?v=BcVAq3YFiuc
Davon abgesehen finde ich sie auch nicht schlecht , sie sind in vielen Situationen nützlich. Sie sind einfach nicht die Wunderwaffe, für die sie in der React-Welt gelobt werden, aber sie haben ihre eigenen Nachteile.
Wie aus der obigen Diskussion hervorgeht, ist die Implementierung von HoCs in Vue nicht so trivial wie in React, da die API und Funktionalität von Vue breiter ist und mehr Grenzfälle berücksichtigt werden müssen.
Wir können sicherlich darüber sprechen, wie wir dies verbessern können, solange es nicht erforderlich ist, irgendetwas in Vue kaputt zu machen - HoCs sind meiner Meinung nach keine bahnbrechende Änderung wert.
666
Die minimalste HoC-Implementierung, die Komponenten mit Slots verarbeiten kann, ist:
function hoc(WrappedComponent) {
return {
render(h) {
return h(WrappedComponent, {
on: this.$listeners,
attrs:this.$attrs,
scopedSlots: this.$scopedSlots,
});
},
};
}
im Vergleich zu den Antworten oben,
Ich habe ein Beispiel geschrieben, um es zu überprüfen
Hilfreichster Kommentar
Okay, also habe ich herumgespielt, um es einfacher zu machen.
Schau mal hier: https://jsfiddle.net/Linusborg/j3wyz4d6/
Ich bin mit der API nicht zufrieden, da es sich um eine sehr grobe Ideenskizze handelt, aber sie kann alles, was sie können sollte.
createHOC
kümmert sich um:$createElement
mit dem vom übergeordneten Element aus, um die richtigen Slots aufzulösen.Das allein ist natürlich nicht sehr hilfreich. Der Spaß passiert also im zweiten Argument, das ein einfaches Komponentenobjekt ist.
Wenn Sie die Renderfunktion selbst schreiben möchten, können Sie dies natürlich tun. Wenn Sie nur Requisiten, Attrs oder Listener erweitern möchten, können Sie den
createRenderFn
-Helfer verwenden. Es erstellt eine Renderfunktion wie die oben beschriebene Standardfunktion, führt jedoch alleattrs
,props
oderlisteners
, die Sie ihm übergeben, mit denen des übergeordneten Elements zusammen.Wenn Sie Ihre eigene Renderfunktion schreiben möchten, können Sie den Helfer
normalizeSlots
verwenden, um das Objekt vonthis.$slots
in ein geeignetes Array zur Weitergabe umzuwandeln:Kommentare erwünscht :)