stagerightlabs / Vue-Three-Demo

An example of a Vue.js / Three.js integration
https://vuethree.stagerightlabs.com/
MIT License
35 stars 8 forks source link

Transfering project to Vue3 and Vuex4 #4

Closed richieracoon closed 2 years ago

richieracoon commented 3 years ago

I kinda tried to transfer this project to vuex4 and i'm somehow getting the same error over and over:

Uncaught (in promise) TypeError: 'get' on proxy: property 'modelViewMatrix' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '#' but got '[object Object]')

Searching for the error has brought me to this post on stackoverflow: https://stackoverflow.com/questions/65693108/threejs-component-working-in-vuejs-2-but-not-3

But the workaround of course doesnt really mention the usage of vuex which should grant reactivity by itself. Can you guess what the issue is?

rydurham commented 3 years ago

Very good question. I have not yet tried porting this project to Vue3 so I have not yet encountered this problem. If I have a moment I will poke around and see if I can find anything. Let me know if you figure it out.

frantortosa commented 2 years ago

Hi guys, a few months have passed and I am about to try this with Vue3 and the latest Vuex, were you finally successful? Do you have a workaround? Otherwise do you think it is possible to integrate threejs into vue3 without using vuex?

richieracoon commented 2 years ago

I couldn't fit it into Vuex but there's definitely a workaround I can show you:

  <div class="simbox">
    <div id="viewport"></div>
  </div>
</template>

<script lang="ts">
import {defineComponent, onMounted, onBeforeUnmount} from 'vue';
import {genSim} from '../threejs/genSim'

export default defineComponent({
  name: 'QuantRegSim',
  props: {
    size: {
      type: Number,
      required: true
    }
  },
  setup() {
    function mountViewer(): void {
      const container: HTMLDivElement = document.getElementById('viewport') as HTMLDivElement;
      genSim(3, container);
    }

    function destroyCanvas(): void {
      const container: HTMLDivElement = document.getElementById('viewport') as HTMLDivElement;
      container.innerHTML = '';
    }

    onMounted(mountViewer);
    onBeforeUnmount(destroyCanvas);

    return {}
  }
});

It is important to call the function that generates the scene in the onMount lifecycle event. I could not have done it a different way. Although it is said in the documentation, that if you call the function, in the "return" section, it would be executed onMount. Same with the onDestroy. If you don't empty your canvas, the scene could be generated twice. Finally the three.js code was placed in a seperate TypeScript-File and the function were imported where I needed them in different components. So it's not really incorporated in vuex, but you can still call the functions from anywhere you want to call them. (sry for my bad english, I'm in a hurry, but I wanted to respond as fast as possible ;-)

rydurham commented 2 years ago

Thank you for this. I haven't had much time available to look at upgrading this project. It is quite possible that the new functional API in Vue 3 would allow us to lean less heavily on vuex here, but I am not entirely sure. This idea you have looks promising.

frantortosa commented 2 years ago

Thank you both for your very quick responses, and in particular for the workaround which has gotten me up and running for now. At least I am not stuck and the project can go on. If I encounter other difficulties (or solutions) I will quickly share with you guys as well.

rydurham commented 2 years ago

Take a look at PR #3 - this should hopefully address this request. I am going to close this issue for now but feel free to reopen if you would like.