Vue: المناقشة: أفضل طريقة لإنشاء ترتيب ذو ترتيب أعلى

تم إنشاؤها على ٢٥ يوليو ٢٠١٧  ·  40تعليقات  ·  مصدر: vuejs/vue

الإصدار

2.4.2

رابط الاستنساخ

https://jsfiddle.net/o7yvL2jd/

خطوات التكاثر

لقد بحثت عن الطريقة الصحيحة لتطبيق HoC باستخدام vue.js. ولكن لم يتم العثور على أي مثال مناسب.
الرابط أدناه معروف بتطبيقات HoC. لكن لم يعمل بشكل متوقع.
https://jsfiddle.net/o7yvL2jd/

كيف يمكنني تطبيق HoC مع vue.js؟
أريد فقط معرفة كيفية تنفيذ HoC بطريقة رد فعل.

ما هو متوقع؟

وهي عبارة عن HoCs التي تعرض المكونات التي تم تمريرها كمعلمات.
HoCs التي تحتوي على فتحات وأحداث ستعرض بشكل طبيعي.

ما الذي يحدث بالفعل؟

العنصر المراد تقديمه مفقود ، أو يختلف الترتيب المعروض عن المكون الأساسي.
لا تعمل بعض تطبيقات HoC مع معالجات الأحداث.

discussion

التعليق الأكثر فائدة

حسنًا ، لقد لعبت مع طريقة لجعل هذا أسهل.

الق نظرة هنا: https://jsfiddle.net/Linusborg/j3wyz4d6/

لست سعيدًا بواجهة برمجة التطبيقات (API) لأنها رسم تخطيطي تقريبي لفكرة ، لكنها قادرة على فعل أي شيء يجب أن تكون قادرة على القيام به.

import { createHOC, createRenderFn, normalizeSlots } from 'vue-hoc'
const Component = {
  props: ['message']
  template: `<p>{{message}}</p>`
}
const HOC = createHOC(Component)

يعتني createHOC بما يلي:

  • نسخ الدعائم من المكون
  • مبادلة $createElement مع ذلك من الأصل لحل الخانات المناسبة.
  • أضف اسمًا
  • إذا لم يتم توفير وسيطة ثانية (كما في المثال أعلاه) ، فإنه يعرض المكون ويمرر:

    • الدعائم

    • أترس

    • المستمعين

    • فتحات عادية

    • فتحات النطاق

هذا بحد ذاته ليس مفيدًا جدًا ، بالطبع. لذا فإن المتعة تحدث في الوسيطة الثانية وهي كائن مكون بسيط.

إذا كنت تريد أن تكتب وظيفة التجسيد بنفسك ، فبالطبع يمكنك ذلك. إذا كنت ترغب فقط في تمديد الدعائم أو attrs أو المستمعين ، فيمكنك استخدام المساعد createRenderFn . ستنشئ وظيفة تصيير مثل الوظيفة الافتراضية الموصوفة أعلاه ولكنها ستدمج أي attrs أو props أو listeners تمررها إليها مع تلك من الوالد.

const HOC = createHOC(Component, {
  mounted() { 
    console.log(`lifecycle hooks work, it's simply component options`) 
  },
  render: createRenderFn(Component, {
    props: {
      message: 'Hello from your HOC!'
    }
  }
})

إذا كنت تريد كتابة دالة العرض الخاصة بك ، فيمكنك استخدام المساعد normalizeSlots لتحويل الكائن من this.$slots إلى مصفوفة مناسبة لتمريرها:

const HOC = createHOC(Component, {
  render(h) {
    return h(Component, {
      props: { message: 'hi from HOC'}, // nothing from parent will be passed on
    }, normalizeSlots(this.$slots))
  }
})

مطلوب تعليقات :)

ال 40 كومينتر

مرحبا @ eu81273

شكرا لاهتمامك بهذا المشروع.

ومع ذلك ، فإن مشكلتك هي سؤال استخدام / دعم ، ومتتبع المشكلة محجوز حصريًا لتقارير الأخطاء وطلبات الميزات (كما هو موضح في دليل المساهمة الخاص بنا).

نحن نشجعك على طرحها على المنتدى أو Stack Overflow أو في دردشة الخلاف الخاصة بنا ويسعدنا مساعدتك هناك.

FWIW ، لقد ألقيت نظرة على المصلحة الشخصية - يجب أن يعمل هذا بنسبة 100 ٪ من الحالات.

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);
 }
});

لقد قمت بتحرير HOC04 في مثالك لأنه كان الأقرب إلى الحل:

https://jsfiddle.net/Linusborg/o7yvL2jd/22/

تحرير: لا تزال مشكلة في الفتحات ، والتحقيق ...

ربما كنت سأحلها: https://jsfiddle.net/BogdanL/ucpz8ph4/. أصبحت الفتحات مشفرة الآن فقط ، ولكن حل هذا أمر تافه.

يبدو أن الحل يتماشى مع طريقة lbogdan ولكن يجب أن يكون لـ createElement طريقة لأخذ الفتحات ، تمامًا كما يمكن أن يستغرق scopedSlots.

ومع ذلك ، لا يزال هناك الكثير من الجهد لإنشاء HoC. هناك الكثير لتتذكره لتمريره ، بينما مع رد الفعل عليك فقط تقديم WrappedComponent مع الدعائم.

لقد فكرت للتو في حل بسيط للغاية ... أخبرني إذا فاتني شيء هنا:

const HOC06 = WrappedComponent => Vue.extend({
   mounted () {
      console.log('mounted 6')
   },
   ...WrappedComponent
})

استنادًا إلى الأمثلة التي قدمها LinusBorg و lbogdan ، فإن أقل تطبيق لـ HoC يمكنه التعامل مع المكونات ذات الفتحات هو:

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,
        });
     }
});

كما ذكر blocka ، لا يزال هناك الكثير من الجهد لإنشاء HoC مع vue.js.

@ eu81273

const HOC06 = WrappedComponent => Vue.extend({
   mounted () {
      console.log('mounted 6')
   },
   ...WrappedComponent
})

يبدو أن هذا اجتياز الاختبار الخاص بك ، أليس كذلك؟ بالطبع ، سيتعين عليك تعديله اعتمادًا على ما إذا كان WrappedComponent مُنشئًا أو كائنًا ، ولكن لا داعي لتمرير الفتحات أو الأحداث أو الدعائم.

لا يزال هناك الكثير من الجهد لإنشاء HoC مع vue.js.

بصرف النظر عن المشكلة المتعلقة بالفتحات ، يرجع هذا فقط إلى حقيقة أن Vue لديها واجهة برمجة تطبيقات أكثر تعقيدًا من React ، والتي تعتبر عيبًا في هذا السيناريو. أنا معجب بـ Reacts الحد الأدنى من واجهة برمجة التطبيقات في هذه الأنواع من حالات الاستخدام - تم تصميم Vue للتو بأهداف تصميم مختلفة قليلاً ، لذلك لا تأتي المكوّنات ذات الترتيب الأعلى بسهولة كما في React.

ولكن يجب أن يكون تافهًا إلى حد ما إنشاء وظيفة مساعدة createHOC() تغطي هذا الإعداد الأولي لك ، أليس كذلك؟

حسنًا ، هذا يعتمد حقًا على الهدف النهائي. بناءً على ما أفهمه ، فإن هدف HoC هو تغيير (تزيين) المكون الأصلي (WrappedComponent) بطريقة ما لإضافة (أو حقن) الدعائم والطرق ومستمعي الأحداث وما إلى ذلك (يشبه إلى حد كبير المزيج ، حقًا: ابتسامة:). يغير المتغير HOC06 تعريف المكون فقط ، ولا يغير طريقة إنشاء مثيله.

blocka غالبًا ما يكون هدف المكوّنات ذات الترتيب الأعلى هو الحصول على الحالة (على سبيل المثال من redux / vuex) وحقنها في دعائم المكون المغلف - وهذا لن يعمل مع نهجك.

تضمين التغريدة كنت أعلم أنه من الجيد جدًا أن يكون حقيقيًا وأنني نسيت شيئًا واضحًا.

أعتقد أن هذا مثال جيد على تنفيذ حالة استخدام حقيقية HoC في Vue: https://github.com/ktsn/vuex-connect.

سيكون Vue Hocs إضافة رائعة (نظرًا لأنه يتم طرحه دائمًا في أي مناظرة vue vs response). ربما يمكن إنشاء ريبو رسمي لتطوير حزمة vue-hoc-creator؟ بهذه الطريقة يمكننا العمل على تنفيذ قوي ومدعوم

بالمناسبة ، حصلت على طريقة أفضل: استخدم $ createElement من المكون الرئيسي بدلاً من المكون HOC الخاص - وهذا يجعل الطفل يحل الفتحات بشكل صحيح:

https://jsfiddle.net/o7yvL2jd/23/

إنه لطيف ، ولكن سببًا إضافيًا لوجود بعض الأدوات الرسمية لذلك نحن
لا يستمر الجميع في إعادة اختراع هذا الرمز.

يوم الأحد 30 يوليو 2017 الساعة 4:33 مساءً ، Thorsten Lünborg [email protected]
كتب:

بالمناسبة ، حصلت على طريقة أفضل: استخدم $ createElement من المكون الرئيسي
بدلاً من HOC الخاص - وهذا يجعل الطفل يحل الخانات بشكل صحيح:

https://jsfiddle.net/o7yvL2jd/23/

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/vuejs/vue/issues/6201#issuecomment-318927628 ، أو كتم الصوت
الخيط
https://github.com/notifications/unsubscribe-auth/AACoury4Fix2jsX_lyTsS6CYOiHJaOuVks5sTOiugaJpZM4Oh0Ij
.

أنا آسف لعدم التوصل إلى حل رسمي بعد. سعيد لأنك تعتقد أنه لطيف بالرغم من ذلك.

الحل الخاص بي ليس مثاليًا أيضًا ، فهناك مشكلات أخرى يجب حلها - على سبيل المثال ، لن تعمل الفتحات المحددة النطاق مع خدعتي الأخيرة.

تحرير: أوه ، لا تهتم ، إنهم يعملون

من المحتمل أن يتم تنفيذ حل رسمي ، على الأقل أتوقع ذلك - لكن يجب التفكير فيه بدقة واختباره.

حسنًا ، لقد لعبت مع طريقة لجعل هذا أسهل.

الق نظرة هنا: https://jsfiddle.net/Linusborg/j3wyz4d6/

لست سعيدًا بواجهة برمجة التطبيقات (API) لأنها رسم تخطيطي تقريبي لفكرة ، لكنها قادرة على فعل أي شيء يجب أن تكون قادرة على القيام به.

import { createHOC, createRenderFn, normalizeSlots } from 'vue-hoc'
const Component = {
  props: ['message']
  template: `<p>{{message}}</p>`
}
const HOC = createHOC(Component)

يعتني createHOC بما يلي:

  • نسخ الدعائم من المكون
  • مبادلة $createElement مع ذلك من الأصل لحل الخانات المناسبة.
  • أضف اسمًا
  • إذا لم يتم توفير وسيطة ثانية (كما في المثال أعلاه) ، فإنه يعرض المكون ويمرر:

    • الدعائم

    • أترس

    • المستمعين

    • فتحات عادية

    • فتحات النطاق

هذا بحد ذاته ليس مفيدًا جدًا ، بالطبع. لذا فإن المتعة تحدث في الوسيطة الثانية وهي كائن مكون بسيط.

إذا كنت تريد أن تكتب وظيفة التجسيد بنفسك ، فبالطبع يمكنك ذلك. إذا كنت ترغب فقط في تمديد الدعائم أو attrs أو المستمعين ، فيمكنك استخدام المساعد createRenderFn . ستنشئ وظيفة تصيير مثل الوظيفة الافتراضية الموصوفة أعلاه ولكنها ستدمج أي attrs أو props أو listeners تمررها إليها مع تلك من الوالد.

const HOC = createHOC(Component, {
  mounted() { 
    console.log(`lifecycle hooks work, it's simply component options`) 
  },
  render: createRenderFn(Component, {
    props: {
      message: 'Hello from your HOC!'
    }
  }
})

إذا كنت تريد كتابة دالة العرض الخاصة بك ، فيمكنك استخدام المساعد normalizeSlots لتحويل الكائن من this.$slots إلى مصفوفة مناسبة لتمريرها:

const HOC = createHOC(Component, {
  render(h) {
    return h(Component, {
      props: { message: 'hi from HOC'}, // nothing from parent will be passed on
    }, normalizeSlots(this.$slots))
  }
})

مطلوب تعليقات :)

تضمين التغريدة

ما أعتقد أنه سيساعد هو الخروج بحالات استخدام حقيقية لـ HoC وحلها باستخدام هذه الأوليات.

قطعا.

أذكر هذه المشكلة (EDIT (mybad): https://github.com/vuejs/vuejs.org/issues/658).
نظرًا لأنك تستخدم $ createElement API غير موثق ، سيكون من المفيد توثيقها لمطوري المكونات الإضافية.

الرابط الخاص بك خاطئ (إلا إذا كنت تريد بالفعل ربط مشكلة من عام 2014)

لكن نعم ، من الناحية الفنية ، لا تزال واجهة برمجة التطبيقات $ceateElement مفقودة في صفحة API.

AlexandreBonaventure هذا الإصدار من vue 0.x أيام. :ابتسامة:
أيضًا ، تم توثيق createElement هنا: https://vuejs.org/v2/guide/render-function.html#createElement -Arguments.

تم توثيق الوظيفة كوسيطة لوظيفة التصيير ، ولكن ليس لأنها متاحة عبر this.$createElement . هناك مشكلة مفتوحة لذلك في vuejs / vuejs.org / issues / 658

LinusBorg لكنها في الأساس نفس الوظيفة التي يتم إرسالها إلى الوظيفة render() ، أليس كذلك؟

بالضبط نفس الشيء. لم يتم توثيقه بوضوح أنه متاح أيضًا خارج وظيفة العرض عبر طريقة المثيل هذه.

أنا فقط أتعامل مع المثال أعلاه وهناك مشكلتان عند استخدامه في سيناريو أكثر تعقيدًا ، ومن ثم الحاجة إلى إعادة شراء رسمية. بضع ملاحظات:

  • يجب على createRenderFn التحقق مما إذا كانت attrs / props / listeners هي وظائف وتقييمها ، فهذا من شأنه أن يسمح لك بتعيين الدعائم ديناميكيًا وما إلى ذلك بناءً على الدعائم الموجودة.
  • بالنسبة للتركيب ، يجب أن يكون المكون هو المعلمة الثانية ، وإذا تم تطبيق طريقة createHOC بأكملها ، فيمكننا بسهولة ربط العديد من المبدعين المخصصين معًا.
  • نظرًا لأنه تمت إضافة hoc على أنه mixin ، إذا حاولت ربط 2 hocs معًا (على سبيل المثال ، withDefaultProps(withProps(component, {}), {}) لا يملك hoc الثاني إمكانية الوصول إلى مثال الدعائم الخاصة بالوالدين

مرحبًا يا رفاق ، لقد كنت أبحث في كتابة تنفيذ لهذا.
https://github.com/jackmellis/vue-hoc/tree/develop
اسمحوا لي أن أعرف ما هو رأيك وسأبحث عن نشره قريبًا. أفكر أيضًا في كتابة حزمة بأسلوب مُعاد تكوينه.

حزمة النمط المعاد تكوينها ستكون رائعة. حقا يمكن أن تستخدم شيئا
مثل withState مؤخرًا.

في يوم السبت ، 19 آب (أغسطس) 2017 الساعة 5:50 صباحًا ، كتب Jack [email protected] :

مرحبًا يا رفاق ، لقد كنت أبحث في كتابة تنفيذ لهذا.
https://github.com/jackmellis/vue-hoc/tree/develop
اسمحوا لي أن أعرف ما هو رأيك وسأبحث عن نشره قريبًا. انا ايضا
التفكير في كتابة حزمة بأسلوب معاد تكوينها.

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/vuejs/vue/issues/6201#issuecomment-323513287 ، أو كتم الصوت
الخيط
https://github.com/notifications/unsubscribe-auth/AACoumQWQMgpVeIvzJ3Ti8A4kLBD04Hhks5sZq_zgaJpZM4Oh0Ij
.

jackmellis عظيم أن تأخذ زمام المبادرة في هذا :)

بضع أفكار حول ملاحظاتك التي قدمتها سابقًا:

  • أعتقد أن النسخة المقلية هي نقطة رائعة ويجب أن تكون "الافتراضي" بطريقة ما ، لأن هذه هي الطريقة التي يتم بها عمل المراكز ذات الترتيب الأعلى بشكل عام ، أليس كذلك؟
  • نقطة جيدة حول مشكلة mixins. هل لديك بالفعل فكرة عن كيفية التخفيف من ذلك؟ ليس لدي واحدة في هذه اللحظة ، ولكن شعوري الداخلي هو أن هذا يجب أن يكون قابلاً للتخفيف في مجموعة من المتغيرات الكاري التي أنشأتها وباستخدام Vue.config.optionsMergeStrategies

فكرت أيضًا في التسمية. لا أحب createRenderFn ، شيء مثل renderComponentWith سيكون أكثر فائدة وأكثر منطقية في سيناريو حيث نقوم بتضمينه في بعض العقد الأخرى:

render(h) {
  return h('DIV', {staticClass: 'some-styling' }, renderComponentWith({ props: {... } }))
}

  • في النهاية اخترت كليهما. لذا فإن createHOC هو المكون الأول غير المطبوخ بالكاري ، ومن ثم هناك متغير كاري createHOCc . النظام البيئي لـ React يركز على الوظائف بشكل كبير ، على عكس Vue ، الذي يعمل بشكل أشبه بإطار عمل OOP. لذلك أعتقد أنه من الأفضل الحفاظ على الاتساق مع بقية Vue ، ولكن مع الاستمرار في تقديم بديل وظيفي.
  • لقد أضفت للتو بعض التعليمات البرمجية للتعامل مع هذا. بدلاً من الحصول على المخصص بالكامل كمزيج ، أقوم بدمج العنصر والخيارات يدويًا معًا باستخدام optionsMergeStrategies. المشكلة الوحيدة في ذلك هي أن optionsMergeStrategies تتوقع vm كمعامل أخير ، لكنني أقوم بعملية الدمج قبل إنشاء مثيل لذلك لا يوجد vm.
  • أنا سعيد جدًا بـ createRenderFn لأن هذا هو بالضبط ما يفعله. لكن كلما جمعت هذا معًا ، قل اعتقادي أن الناس سيستخدمونه بشكل مباشر. سيكون الاستخدام العام مثل:
const hoc = createHOC(
  Component,
  {
    created(){
      /* ... */
    }
  },
  {
    props: (props) => ({
      ...props,
      someProp: 'foo'
    })
  }
);

ربما لا أفهم مثالك تمامًا؟

ربما لا أفهم مثالك تمامًا؟

لا ، أعتقد أنك على المسار الصحيح ، كانت أفكاري تسير في اتجاه مماثل عندما فكرت في المزيد عنها بعد ردي الأخير.

في POC الأولي الخاص بي ، قمت بتضمينه حتى يتمكن الأشخاص من إضافة ترميز إضافي حول المكون الذي تم عرضه ، ولكن هذا يعني أنه لم يعد حقًا HOC بعد الآن ، لأنه سيجلب واجهة المستخدم أيضًا ...

نعم ، أعتقد أنك تحاول تقديم محتوى إضافي ، لقد خرجت من منطقة HOC وربما تنشئ أيضًا SFC للتعامل معها.

لقد نشرت للتو vue-hoc على npm!

لقد كنت أعمل أيضًا على إعداد vue-compose وهو عبارة عن جلسة توثيق سريعة بعيدًا عن الاستعداد أيضًا. على الرغم من أنه يشبه إعادة التكوين ، إلا أن Vue يتعامل مع الكثير من الأشياء الذكية (مثل التخزين المؤقت للحسابات ويشجع على استخدام this ) لذلك فهو في الواقع لا يحتاج إلى بناء جملة معقد (أو نمط وظيفي).

يعمل extends بشكل مختلف ، لكن يمكن استخدامه لتحقيق نتائج مماثلة ، هذا صحيح.

سأغلق هذا لأنني أعتقد أن مشروع jackmellis يوفر أساسًا متينًا. لا ننوي تضمين طريقة لإنشاء المكوّنات ذات الترتيب الأعلى إلى جوهر ، وذلك لأننا لا نرى فائدة كبيرة على الخلطات / الامتدادات.

في الأساس لأننا لا نرى فائدة كبيرة على الخلطات / الامتدادات.

LinusBorg لقد تخلت React بالفعل عن mixin ، يجلب HOC الكثير من الفوائد.

قامت هذه المقالة بتحليل الفوائد:

  • العقد بين المكون وخلطاته ضمني.
  • عندما تستخدم المزيد من mixins في مكون واحد ، فإنها تبدأ في التعارض.
  • تميل Mixins إلى إضافة المزيد من الحالة إلى المكون الخاص بك بينما يجب أن تسعى للحصول على أقل.
  • ....

أعتقد أن فريق Vue يجب أن يفكر في دعم HoC بعناية أكبر .... على الرغم من أنه ليس سهلاً (يبدو أن Vue غير مصمم بهذه الطريقة).

أنا لست مقتنعًا بأن HoCs هي مفهوم متفوق. يمكن أن تحدث الاشتباكات المحتملة "العقد الضمني" مع رؤساء الهيئات كذلك ، على سبيل المثال.

شاهد هذا الحديث من قبل مشرف React-router حول هذا الموضوع: https://www.youtube.com/watch؟v=BcVAq3YFiuc

ومع ذلك ، لا أعتقد أنهم سيئون أيضًا ، فهم مفيدون في العديد من المواقف. إنهم ليسوا فقط الحل السحري الذي يتم الإشادة بهم كما هو الحال في عالم React ، على الرغم من أن لديهم سلبياتهم الخاصة.

كما يتضح من المناقشة أعلاه ، فإن تنفيذ HoCs في Vue ليس تافهًا كما هو الحال في React لأن واجهة برمجة تطبيقات Vue ووظائفها أوسع ويجب الاهتمام بالمزيد من الحالات المتطورة.

يمكننا بالتأكيد التحدث عن كيفية تحسين هذا طالما أنه لا يتطلب كسر أي شيء في Vue - لا تقلق HoC من تغيير جذري في وجهة نظري.

666

الحد الأدنى من تنفيذ HoC الذي يمكنه التعامل مع المكونات ذات الفتحات هو:

function hoc(WrappedComponent) {
  return {
    render(h) {
      return h(WrappedComponent, {
        on: this.$listeners,
        attrs:this.$attrs,
        scopedSlots: this.$scopedSlots,
      });
    },
  };
}

مقارنة بالردود أعلاه ،

  • لا حاجة لتكوين الخاصيات ، والذي يمكن أن ينتقل من هذا $ attrs إلى الطفل
  • ليست هناك حاجة إلى فتحات إضافية ، فتحات $ scoped تحتوي على فتحات منذ الإصدار v2.6.0 +

لقد كتبت مثالا للتحقق

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات