Skip to content

Discussion: Best way to create a HOC #6201

Closed
@eu81273

Description

@eu81273

Version

2.4.2

Reproduction link

https://jsfiddle.net/o7yvL2jd/

Steps to reproduce

I've searching for the right way to implement HoC with vue.js. But couldn't found any suitable example.
The link below is known HoC implementations. But didn't work expected.
https://jsfiddle.net/o7yvL2jd/

How can I implement HoC with vue.js?
I just want to know how to implement HoC in the react.js way.

What is expected?

They are HoCs that simply renders components passed in as parameters.
HoCs containing slots and events will render normally.

What is actually happening?

The element to be rendered is missing, or the rendered order differs from the baseComponent.
Some HoC implementations do not work with event handlers.

Activity

LinusBorg

LinusBorg commented on Jul 25, 2017

@LinusBorg
Member

Hello @eu81273

Thank your for your interest in this project.

However, your issue is a usage/support question, and the issue tracker is reserved exclusively for bug reports and feature requests (as outlined in our Contributing Guide).

We encourage you to ask it on the forum , Stack Overflow or on our discord chat and are happy to help you out there.

LinusBorg

LinusBorg commented on Jul 25, 2017

@LinusBorg
Member

FWIW, I took a look out of personal interest - this should work 100% of cases.

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

I edited HOC04 in your example since it was the closest to the solution:

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

Edit: still an issue with slots, investigating ...

lbogdan

lbogdan commented on Jul 26, 2017

@lbogdan
Contributor

I might have solved it: https://jsfiddle.net/BogdanL/ucpz8ph4/. Slots are just hardcoded now, but that's trivial to solve.

blocka

blocka commented on Jul 26, 2017

@blocka

Seems the solution is along the method of @lbogdan but createElement should have a way of taking slots, just like it can take scopedSlots.

However, it is still a lot of effort to create an HoC. There's a lot to remember to pass through, while with react you just render the WrappedComponent with props.

blocka

blocka commented on Jul 26, 2017

@blocka

I just thought of a very simple solution...let me know if I'm missing something here:

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

eu81273 commented on Jul 26, 2017

@eu81273
Author

Based on the examples given by @LinusBorg and @lbogdan, the most minimal HoC implementation that can handle components with slots is:

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

As @blocka mentioned, it is still a lot of effort to create an HoC with vue.js.

blocka

blocka commented on Jul 26, 2017

@blocka

@eu81273

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

This seems to pass your test, no? Of course, you would have to adjust it depending on whether WrappedComponent is a constructor or object, but no need to pass slots, events or props.

LinusBorg

LinusBorg commented on Jul 26, 2017

@LinusBorg
Member

it is still a lot of effort to create an HoC with vue.js.

Apart from the issue with slots, this is just due to the fact that Vue does have a more complex API than React, which in this scenario is a disadvantage. I admire Reacts minimal API in these kinds of use cases - Vue was just designed with slightly different deign goals, so HOCs don't come as easily as in React.

But it should be fairly trivial to create a createHOC() helper function that wraps this initial setup for you, shouldn't it?

lbogdan

lbogdan commented on Jul 26, 2017

@lbogdan
Contributor

Well, it really depends what the end goal is. From what I understand, the goal of HoC is to somehow change (decorate) the original component (WrappedComponent) to add (or inject) props, methods, event listeners etc. (much like a mixin, really 😄 ). HOC06 variant only changes the component definition, it doesn't change the way in which it's instantiated.

LinusBorg

LinusBorg commented on Jul 26, 2017

@LinusBorg
Member

@blocka The goal of HOCs often is to get state (e.g. from redux / vuex) and inject it into the wrapped component's props - that would not work with your approach.

changed the title [-]How to implement HoC correctly[/-] [+]Discussion: Best way to create a HOC[/+] on Jul 26, 2017
blocka

blocka commented on Jul 26, 2017

@blocka

@LinusBorg right. I knew it was too good to be true and that I was forgetting something obvious.

43 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @blocka@posva@LinusBorg@lbogdan@anson09

        Issue actions

          Discussion: Best way to create a HOC · Issue #6201 · vuejs/vue