0

I have a component that has complex rendering logic. I try to carry out this logic to helper classes, for simplifying. To do this, in the data section (for reactivity), I create class references as follows:

export default {
  data: () => ({
    state: new InitialState(this),
    query: new QueryController(this)
  })
}

As I understand it, at this point the context of this is not yet defined. So, I have two questions.

1) Is there a way to pass the this component context in the data section (without lifecycle hooks)?

2) Is the approach with references to external classes of vuejs philosophy contrary?

3 Answers 3

2

Component instance is already available when data function runs, this is one of reasons why it has been forced to be a function.

Due to how lexical this works with arrow functions, it's incorrect to use them to access dynamic this. It should be:

  data() {
    return {
      state: new InitialState(this),
      query: new QueryController(this)
    };
  })

The problem with InitialState(this) is that the entire component instance is passed instead of relevant data, this breaks the principle of least privilege.

Despite Vue isn't focused on OOP, there's nothing wrong with using classes. One of possible pitfalls is that classes may not play well with Vue reactivity because it puts restrictions on the implementation. Another pitfall is that classes cannot be serialized to JSON and back without additional measures, this introduces limitations to how application state can be handled.

Sign up to request clarification or add additional context in comments.

Comments

1

As I understand it, at this point the context of this is not yet defined.

Only because of the way you've written the code. The component instance does exist and is available. It is sometimes used to access the values of props for determining the initial values of data properties.

For example, here is an example from the documentation:

https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow

export default {
  props: ['initialCounter'],
  data: function () {
    return {
      counter: this.initialCounter
    }
  }
}

The reason why your code doesn't work is because you are using an arrow function. If you change it to the following then this will be available:

export default {
  data () {
    return {
      state: new InitialState(this),
      query: new QueryController(this)
    }
  }
}

See also the note here:

https://v2.vuejs.org/v2/api/#data

Note that if you use an arrow function with the data property, this won’t be the component’s instance, but you can still access the instance as the function’s first argument

As to your other question about whether using classes like this is contrary to Vue...

I don't think the use of classes like this is encouraged but they can be made to work so long as you understand the limitations. If you have a clear understanding of how Vue reactivity works, especially the rewriting of properties, then it is possible to write classes like this and for them to work fine. The key is to ensure that any properties you want to be reactive are exposed as properties of the object so Vue can rewrite them.

If you don't need reactivity on these objects then don't put them in data. You'd be better off just creating properties within the created hook instead so the reactivity system doesn't waste time trying to add reactivity to them. So long as they are properties of the instance they will still be accessible in your templates, there's nothing special about using data from that perspective.

Comments

0

I think computed is a better way to do what you want

export default {
    computed:{
        state(){
            return new InitialState(this);
        },
        query(){
            return new QueryController(this);
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.