1
votes

I am trying to reset data passed as props to children components. How should i write this ?

Context: i'm converting a ThreeJS implementation into Vue/Typescript. It includes a controls panel composed with slider inputs controlling parameters of the Three canvas. I separated this massive monolithic original code into 3 components : - child1: the controlsPanel, contains sliders and the reset button - child2: the Vue-GL canvas, emitting mouse events - parent: the component hosting initial data, and reseting.

parent :

<template>
  <div>
    <child1 :prop1="prop1" :prop2="prop2" :child1Prop="child1Prop" :reset="reset" />
    <child2 :prop1="prop1" :prop2="prop2" :child2Prop="child2Prop" />
  </div>
</template>

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

  import Child1 from './components/Child1.vue';
  import Child2 from './components/Child2.vue';

  const initialState = {
    prop1: 1,
    prop2: 2,
    child1Prop: 'some text',
    child2Prop: 'another text',
  }
  export type InitialState = typeof initialState;

  @Component({
    components: {
      Child1,
      Child2,
    },
  })
  export default class App extends Vue {
    public prop1!: InitialState['prop1'];
    public prop2!: InitialState['prop2'];
    public child1Prop!: InitialState['child1Prop'];
    public child2Prop!: InitialState['child2Prop'];

    public beforeMount() {
      Object.assign(this, initialState);
    }

    public reset() {
      Object.assign(this, initialState);
    }
  }
</script>

Child code :

<template>
...
<!-- this button is only in Child1 -->
<button type="button" @click="resetCamera">Reset</button>
</template>

<script lang="ts">
  // import VueAsyncComputed, { IAsyncComputedProperty } from 'vue-async-computed';
  import { Component, Prop, Vue } from 'vue-property-decorator';
  import { InitialState } from '../App.vue';

  @Component
  export default class ChildX extends Vue {
    @Prop() public prop1!: InitialState['prop1'];
    @Prop() public prop2!: InitialState['prop2'];
    @Prop() public childXProp!: InitialState['childXProp']; // Specific prop

    // computed getters and methods using this.prop1 etc...

    // this method is only in Child1
    public resetCamera() {
      this.reset();
    }
  }
</script>

Properties prop1 and prop2 are controlled by Child1 component and consumed by Child2. Child2 can also update these props (via mouse events), which should update sliders in Child1 appropriately.

I managed to make Typescript happy, but at the cost of typings everywhere...

Question1: is there a way to simplify while keeping the 2way-bindings between childs and parent App ? (2way-bindings don't work with above code)

Question2: How to reset all props ? my child1.resetCamera seems to call parent reset() but props are not reseting ...

1
Props aren't supposed to be two-way binding. Their main purpose is "pass this object from parent to child", that's it. Changing props in children may create problems because it may be hard to know what's changing your data: parent or child? My suggestion: use props as "current data", so when you reset them, it'll be simply done by changing the props, once it'll reflect on the children components. Instead of changing the props inside the children components, emit events and catch them in the parent and then decide what to do (change props, maybe). - wcosta
thanks, your suggestions pointed my thoughts towards v-model : i implemented a single v-model object containing common props for both children, and put it in both children props. Result github.com/Sharlaan/webgl-area-picking-vue It works partially in the sense that updating with mouse from the webgl container does not update the sliders. Working on reset now, with your suggestion. - Masa
That's great. I'll post it as an answer then - wcosta

1 Answers

0
votes

When you use props, you should be careful about the point of this kind of data: its main purpose is simply to pass data from parent to child, that is it.

As you might figure that out later, usually it is not a good idea to change props both in parent and child. Why? Consider the following example:

A parent component called mainComponent passes currentID to all its children: headerComponent and footerComponent. However, if you have designed your props to be changed by both parent and children, if footerComponent changes currentID it also changes in headerComponent which may not be expected. How about a third child component being added to your parent component that uses currentID as well? It will be affected too.

Using the above example, my suggestion is: use props in only one-way binding. In other words, mainComponent passes currentID to all its children. If any of these needs to change that props, emit an event by using $emit("updateCurrentID", newCurrentID) and catching this up in the mainComponent and, finally, change currentID and that will reflect on all children. But now, you are sure you are updating this props data in only one place (mainComponent).

To emit that, I can think of two possibilities: by $emit itself (docs) or by creating your own custom events, as you can see here - a tutorial by MDN.

Hope it helps