Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

PROBLEMA: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "ndrawer" found in

Olá Flávio, Tudo bem?

Sou novo no curso de vue 2.0, estou começando a criar alguns componentes, só que estou recebendo o seguinte problema no console.

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "ndrawer"
found in

Devo estar passando minha prop da maneira errada.

Estou querendo em App.vue criar inserir um componente chamado Navigation.vue ele faz comunicação pelo v-model.

meu componente está escrito assim.

Navegation.vue

<template>
    <v-navigation-drawer v-if="loggedIn" fixed :mini-variant="true" :clipped="false" v-model="ndrawer" class="secondary" app>
      <v-list class="primary">
        <v-list-tile v-for="(item, i) in items" :key="i" value="true">
          <v-list-tile-action>
            <v-icon style="color:#fff;" light v-html="item.icon"></v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title style="color:#fff;" v-text="item.title"></v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
    </v-navigation-drawer>
</template>
<script>
export default {
  props: [
    'loggedIn',
    'ndrawer'
  ],
    data() {
      return {
        items: [{
          icon: 'library_add',
          title: 'Biblioteca'
        }],
      }
    }, 
}
</script>

Chamada principal dele é está

App.vue

<template>

  <v-app light>
    <dr-navigation :loggedIn="$store.state.isUserLoggedIn" :ndrawer="drawer">
    </dr-navigation>

    <dr-toolbar :loggedIn="$store.state.isUserLoggedIn">
      <v-layout row justify-space-between>
        <v-flex xs2 style="margin-top:12px;">
          <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
        </v-flex>
        <v-flex xs2>
          <center>
            <img src="/static/logo-domrock-nav.png" alt="Dom Rock" />
          </center>
        </v-flex>
        <v-flex xs2 style="margin-top:12px;">
          <div style="float:right;">
            <v-btn icon @click.stop="rightDrawer = !rightDrawer">
              <v-icon>menu</v-icon>
            </v-btn>
          </div>
          <v-spacer></v-spacer>
          <div style="float:right;">
            <v-btn icon @click="onLogout()">
              <v-icon>person</v-icon>
            </v-btn>
          </div>
        </v-flex>
      </v-layout>
    </dr-toolbar>

    <dr-footer></dr-footer>
  </v-app>
</template>

<script>
  import Toolbar from '@/components/Shared/ToolBar'
  import Navigation from '@/components/Shared/Navigation'
  import Footer from '@/components/Shared/Footer'

  export default {
    components: {
      'dr-toolbar': Toolbar,
      'dr-navigation': Navigation,
      'dr-footer': Footer,
    },
    data() {
      return {
        clipped: false,
        drawer: true,
        fixed: false,
        miniVariant: false,
        right: true,
        rightDrawer: false,
        title: ''
      }
    },
    methods: {
      onLogout() {
        alert("deslogar")
      },
    }
  }
</script>

<style lang="stylus" scoped>
@import "../stylus/login"
</style>

O problema está em :ndrawer="drawer" está variavel estou realizando a interpolação passando em 2 componentes só que quando fecho o sidebar recebo a seguinte mensagem

vue.runtime.esm.js?a427:570 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "ndrawer"

found in

---> <DrNavigation> at src/components/Shared/Navigation.vue
       <VApp>
         <App> at src/App.vue
           <Root>

Se você conseguir me dar uma luz já vai ajudar e muito.

3 respostas

Bom dia.

Você está usando qual versão do Vue? Vi uma série de componentes que não parecem ser padrões do Vue? Viu se é algum bug nesses componentes ou versão do Vue?

solução!

Acredito que isto esteja acontecendo porque você está mudando o valor da prop diretamente.

Lembre-se que todas as props no Vue 2 sãoone-way, ou seja, Pai para Filho.

Quando você altera o valor da prop no componente Filho, o componente Pai não irá receber esta atualização.

Não sei como está o seu conhecimento eu Vue, então vou dar duas dicas bem básicas.

Opção - 1

this.$emit: Ao realizar alguma alteração diretamente na props, será necessário enviar um evento para o componente Pai dizendo que houve alterações.

Exemplo:

      this.meuNome = 'Max'
      this.$emit('resetarNome', this.meuNome)

No componente Pai você irá receber através da diretiva v-on. Exemplo:

            <div class="col-xs-12 col-sm-6">
                <app-user-detail
                :meuNome="nome"
                @resetarNome="nome = $event">
                </app-user-detail>
            </div>

Opção - 2

Passar uma props como função de callback, exemplo:

Componente Filho - UserDetail

<template>
    <div class="component">
        <p>user Name: {{ meuNome }}</p>
        <button @click="resetFn()">Resetar Nome</button>
    </div>
</template>

export default {
  props: {
    meuNome: {
      type: String
    },
    resetFn: Function
  },
};

Componente Pai

<template>
            <div class="col-xs-12 col-sm-6">
                <button @click="mudarNome">Mudar seu nome</button>
                <app-user-detail
                :meuNome="nome"
                :resetFn="resetarNome">
                </app-user-detail>
            </div>
</template>

  export default {
    data() {
      return {
        name: 'Mathews',
      }
    },
    methods: {
      mudarNome() {
        this.name = 'Anna'
      },
      resetarNome() {
        this.name = 'Mathews'
      }
    },
    components: {
      appUserDetail: UserDetail
    }
  }

OBS: Parece que você está usando Vuetify. Verifique a versão que você está usando e tente buscar alguns exemplos para saber se é algum BUG da versão utilizada.

Valeu Pessoal pela ajuda!!!

Então, Sou novo em Vue 2.0 e tentado aprender as boas práticas do Javascript.

E realmente estava implementando da forma errada, tentando mudar diretamente o valor da prop, estava entrando em conflito.

O Mathews deu uma dica essencial usar o

this.$emit

Resolveu a parada, lógico que ainda acho que estou fazendo gambiarra, não entendi o que está acontecendo nos meus métodos,

Ficou assim

App.vue

<template>
  <v-app light>


    <dr-navigation :loggedIn="$store.state.isUserLoggedIn" :drawer= "drawer" >
    </dr-navigation>

  </v-app>
</template>
<script>
  import Navigation from '@/components/Shared/Navigation'
  export default {
    components: {
      'dr-navigation': Navigation,
    },
    data() {
      return {
        drawer: true,
      }
    },
    methods: {
      onLogout() {
        this.$store.dispatch('setToken', null)
        this.$store.dispatch('setUser', null)
        this.$router.push({
          name: 'login'
        })
      },
    }
  }
</script>

Navigation.vue

<template>
    <v-navigation-drawer v-if="loggedIn" fixed :mini-variant="true" :clipped="false" v-model="drawerFlag" class="secondary" app>
      <v-list class="primary">
        <v-list-tile v-for="(item, i) in items" :key="i" value="true">
          <v-list-tile-action>
            <v-icon style="color:#fff;" light v-html="item.icon"></v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title style="color:#fff;" v-text="item.title"></v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
    </v-navigation-drawer>
</template>
<script>
export default {
  props: [
    'loggedIn',
    'drawer'
  ],
    data() {
      return {
        drawer: true,
        items: [{
          icon: 'library_add',
          title: 'Biblioteca'
        }],
      }
    },

    computed: {
      drawerFlag: {
        get: function() {
          return this.drawer
        },
        set: function(val) {
          this.$emit('emitterdrawer', val)
        }
      }
    },
}
</script>

Criei um método drawerFlag em computed nele eu pego a propriedade drawger , passando em set o $emit nesse formato, não sei explicar o que aconteceu, porque no primeiro parametro do emit onde passo a string, pode ser qualquer nome ali, mas resolveu, não estou recebendo mais o erro no console.

Valeu Flávio, Valeu Mathews sua dica foi essencial.