Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Utility functions in Vue component inside or outside component

What would be preferred way to register functions in Vue Component. I tend to register in component only methods that are required by view (or require direct component data access) and other functions that are not required by view outside vue component. The assumption is that utilityFunction() and utilityFunctionTwo() are currently used only inside this component.

This is an example:

<template>
    <button @click="bar"></button>
    <button @click="foo"></button>
    <button @click="baz"></button>
</template>

<script>
  export default {
      name: "SampleComponent",
      data() {
          return {
              someVariable: "ABC",
              otherVariable: 123
          }
      },
      methods: {
          foo() {
              //some logic
              utilityFunction(this.someVariable);
              //other logic
          },
          bar() {
              //some logic
              utilityFunction(this.someVariable);
              utilityFunctionTwo(this.otherVariable);
              //some other logic
          },
          baz() {
              //some logic
              utilityFunctionTwo(this.someVariable);
              //some other logic
          }
      }
  }
  function utilityFunction(arg){
      //do something
  }
  function utilityFunctionTwo(arg){
      //do something
  }
</script>

Arguments may be different, utility functions can be pure and return something or mutate argument. There can be a lot of different scenarios. But I hope you have got the point.

The other approach to do it is to add those functions as methods to your component. Like this:

<template>
    <button @click="bar"></button>
    <button @click="foo"></button>
    <button @click="baz"></button>
</template>

<script>
    export default {
        name: "SampleComponent",
        data() {
            return {
                someVariable: "ABC",
                otherVariable: 123
            }
        },
        methods: {
            foo() {
                //some logic
                this.utilityFunction();
                //other logic
            },
            bar() {
                //some logic
                this.utilityFunction();
                this.utilityFunctionTwo(this.otherVariable);
                //some other logic
            },
            baz() {
                //some logic
                this.utilityFunctionTwo(this.someVariable);
                //some other logic
            },
            utilityFunction() {
                //do something
                console.log(this.someVariable)
                //other stuff
            },
            utilityFunctionTwo(arg) {
                //do something
            }
        }
    }
</script>

In this approach you sometimes don't need to pass argument to method, as it have access to components data object.

I slightly prefer first approach due reasons:

  1. I have short list of methods used by template or required by component (for some reason). Sometimes this list can get quite long if all methods are put there.
  2. If function will be usable elsewhere in the future I will able to easily add it to some .js file and import it in other components.
  3. Functions does not have access to components scope if they don't need to
  4. It saves me from typing this keyword ;-) And sometimes might be useful if used inside lambda.

I am not sure if this is a matter of opinion and you can prefer one over the other approach purely by your personal preferences or are they any objective reasons that you should prefer one over the other, like (but not limited to) performance of component or principles of software design that are broken by one solution.

like image 883
Zychoo Avatar asked Sep 25 '19 09:09

Zychoo


People also ask

What is @vueuse/components?

In v5.0, we introduced a new package, @vueuse/components providing renderless component versions of composable functions. For example of onClickOutside instead of binding the component ref for functions to consume: We can now use the renderless component which the binding is done automatically:

What is the difference between functional and non-functional components in Vue?

The non-functional components deal with .native events automagically, while the functional component is not sure if there's even a root element to apply the .native events, so Vue exposes the data.nativeOn property for you to handle the .native events the you want. <MyTitle title="Let's go to the mall, today!" class="super-bold-text" />

How to create a Vue component with Vue CLI?

Each component is in a .vue file. All components must include a template tag and a script. A style tag may also be added to style the template. Here’s an example of a simple Vue component created with Vue CLI: The object after export default is just like the component object in the CDN version.

How to inherit all functions of a component in Vue?

For example, instead creating a component Validators.vue as you did in your example, you can create a mixin named Validators.js as per below: In this way, the component CompA will inherit all the functions, data and computed property defined in the mixin.


1 Answers

The difference is that utilityFunction and utilityFunctionTwo helper functions are untestable. They can't be accessed directly. They couldn't be mocked, even if they were:

  export function utilityFunction(arg){
      //do something
  }

  export function utilityFunctionTwo(arg){
      //do something
  }

As explained here, due to how modules work, it's possible to spy or mock a function only if it was exported from a module and is used in another module.

In order to be fully testable or reusable, utilityFunction and utilityFunctionTwo should be moved to another module.

Since they are used privately by a component and aren't reused, a reasonable alternative is to make them private methods, this can be designated with underscore notation:

    methods: {
        ...
        _utilityFunction() {
            //do something
        },
        _utilityFunctionTwo(arg) {
            //do something
        }
    }

A downside is that methods cannot be automatically removed as dead code in case they aren't used, but regular functions can.

like image 197
Estus Flask Avatar answered Oct 26 '22 17:10

Estus Flask