简体   繁体   中英

How can I, in Vue, define a local data property that uses a prop as its initial value, in Typescript syntax?

When passing a prop to a child component in Vue, the documentation says:

In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.

The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards. In this case, it's best to define a local data property that uses the prop as its initial value:

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

We are using typescript. The syntax for "defining a local data property" is as follows ( to my understanding ):

<script lang="ts">
import Vue from 'vue'
import { Component } from 'vue-property-decorator'

@Component
export default class App extends Vue {
  // Data property
  myDataProperty: string;
</script>

And the syntax for a prop is:

@Component
export default class App extends Vue {
  // Makes a "exampleProperty" a component prop with the default value of 'Example'
  @Prop({default: 'Example'})
  exampleProperty: string
}

So, we tried to follow the documentation, and ended up with:

parentComponent.vue

<template>
  <childComponent testProperty='test' />
</template>

childComponent.vue

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class childComponent extends Vue {
  @Prop(
    {
      default: 'notTest',
      validator: (component) => {
        return [
          'notTest',
          'test',
        ].indexOf(component) > -1;
      },
    },
  )
  testProperty!: string;
  testProperty = this.testProperty;
</script>

That, predictably, errored with `Duplicate identifier testProperty.

So, we tried

...
      testProperty!: this.testProperty;
...

which resulted in

Duplicate identifier 'testProperty'. Property 'testProperty' has no initializer and is not definitely assigned in the constructor. Subsequent property declarations must have the same type. Property 'testProperty' must be of type 'this', but here has type 'any'.

So, I decided to try the "vue-class-component" decorator.

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component({
  data: function(){
    return {
      testProperty: this.testProperty,
    }
  }
})
export default class childComponent extends Vue {
  @Prop(
    {
      default: 'notTest',
      validator: (component) => {
        return [
          'notTest',
          'test',
        ].indexOf(component) > -1;
      },
    },
  )
  testProperty!: string;
  testProperty = this.testProperty;
</script>

This resulted in the error Property 'testProperty' does not exist on type 'Vue'.

I would like to, in a handler, do this.testProperty = 'newProperty' at some point, but cannot, because that would be directly modifying a prop.

How can I define a local data property that uses a prop as its initial value in Typescript?

EDIT:

If I do none of the above, and simply define the prop, with no attempt to define a local data property that uses the prop as its initial value, and then do

this.testProperty = 'test'

in a handler, this error is displayed in the chrome console:

vue.runtime.esm.js[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: "testProperty"

I will summarise my comments into a single coherent answer: the problem you are seeing is that you have already defined this.testProperty by declaring it as a prop: doing testProperty = this.testProperty is a circular reference at best. Using the @Prop decorator alone will do the mapping of the attribute in the template to the variable.

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class childComponent extends Vue {
  @Prop(
    {
      default: 'notTest',
      validator: (component) => {
        return [
          'notTest',
          'test',
        ].indexOf(component) > -1;
      },
    },
  )
  testProperty!: string;

  // Map prop to local data property
  testPropertyLocal = this.testProperty;
</script>

Also, remember this caveat: VueJS properties must be kebab-case in templates and camelCase in JS . So, you need to update your child component reference to:

<template>
  <childComponent test-property='test' />
</template>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM