Reuse/reuse of reactive Vue component

Asked

Viewed 1,438 times

9

I’m trying to repurpose components in Vuejs, one of my attempts is to reuse form fields, example:

I have in several forms of my site the fields login and password, so I created a component called userform:

<template>
    <section>
        <input v-model="login">
        <input v-model="password" type="password">
    </section>
</template>

<script>

export default {
    name: "userform",
    data(){
        return {
            login: 'blabla',
            password: ''
        }
    }
}
</script>

The idea now is to take the component userform created and reused in several components to form forms, for example in the component of login:

<template>
    <section class="col-md-4 col-md-offset-4">

        <userform></userform>
        <button @click="sendLogin()">
            Logar
        </button>

    </section>
</template>

<script>

import userform from './../../forms/userform.vue'

export default {
    name: "login",
    components: {userform},
    mixins: [userform],
    methods: {
        sendLogin() {
            console.log( "Usuario " +  userform.data().login )
            console.log( "Senha " + userform.data().password )
        }
    }
}
</script>

But the reactivity doesn’t work when I enter the component login the data of login and password are even caught, but are never changed, always the output on the console is:

Usuario blabla
Senha 

How do I make reactivity work in this case? Am I using it the right way? Could you give an example of how this kind of reuse is done? I’m having a hard time learning this part.

1 answer

7


Components serve to be reused, it would not be necessary to use the mixin, which is reuse of component fragments.

You got two problems there:

Mixin injects values into components, but their values are not shared

The Mixin serves so that you do not need to repeat codes on different components that have some function/data in common, but they are not shared with each other, if you change one, does not change the other, the Vue does not allow this¹. How are you using the mixin within the component login that is carrying its component userform, you’re just replicating the value of userform inside login (you can check on Vuedevtools).

O componente Login também tem os valores, mas a reatividade só acontece no userform

But that’s not the cause of your problem, so let’s get to it...

Call userform directly, causes you to select the object userform of the component Login imported and not the component userform in itself.

I don’t know for sure if that’s the behavior, but in calling userform you are calling the instantiated object within components: { userform }, because think about me, and if you had 2 tags <userform>, which one would you access? The reactivity is inherent to each component, independently.

[tl;dr] So he takes the value of the object userform, that is with the predefined values, which will only change if you move the object, but even so, without changing the value of the components, which are already other objects.

Solution: Reference

One way around this problem is by using the references. To use them, you must add property ref in the component and access it using this.$refs.nome_da_ref.nome_do_dado.

Ex(myComponent.Vue component):

<template>
  <input v-model='x'>
</template>  
<script>
export default {
  data (){
    return {
      x: 10
    }
  }
}
<script>

Ex(Test component.Vue):

<template>
  <my-component ref='meuComponent'>
</template>
<script>
import myComponent from './myComponent'

export default {
  components: { myComponent }
  methods: {
    showData() {
      console.log(this.$refs.x);
    }
  }
}
<script>

As soon as you change the input value of <my-component> the reactivity works and the method showData() printara the entered value.

Upshot

Some changes need to be fairs in the component login:

  1. Remove the mixin
  2. Add the reference
  3. Change your method to use the reference instead of the object

Code:

<template>
    <section class="col-md-4 col-md-offset-4">

        <userform ref='meuForm'></userform>
        <button @click="sendLogin()">
            Logar
        </button>

    </section>
</template>

<script>

import userform from './../../forms/userform.vue'

export default {
    name: "login",
    components: {userform},
    methods: {
        sendLogin() {
            console.log( "Usuario " +  this.$refs.meuForm.login )
            console.log( "Senha " + this.$refs.meuForm.password )
        }
    }
}
</script>

That should solve.

Recommendations and Conventions

  • If you want to use the same data globally, for several components in the same view, I suggest you take a look at Vuex.

  • Use some prefix on your components, this may prevent headaches later (third-party components with the same name, existing HTML components, etc).
    Ex: <lvcsUserForm> or <lvcs-user-form>.

  • Treat components as objects that are, using camelCase in their names during the import, and repeat them in the archives.
    It even helps you, you don’t need the attribute name in the component, and it may have its tag written in two ways, with Pascalcase or kebab-case, but this is defined by the name used in import, as import MeuForm from './../../forms/userform' may be used as <MeuForm> or <meu-form>.

    *Obs: The same does not work for props, they shall be appointed in camelCase and will always be written in kebab-case in the component, eg. <meu-form my-prop="10">.

  • 1

    Thank you very much, I had researched about it but it was all using the emit, which I think would be more for communication between the components and not references between values. Clarified a lot!

  • 1

    The $Emit is usually used to drop a flag (give a sign) that something happened, the problem is that the child component casts the value to the father, but for this there has to be an event*, something has to happen in the child, so there is no reactivity. * The send function and button would have to be in userform

  • That’s what I call an answer! That’s right, thank you !

Browser other questions tagged

You are not signed in. Login or sign up in order to post.