Every time I switch views using the router in vue.js, my three.js canvas gets replicated

After creating a Vue.js integrated with three.js application, I encountered an issue with the canvas getting duplicated every time I opened the view containing the three.js application. The canvas remained visible below the new view, as shown in this image:

https://i.stack.imgur.com/3kigr.png

In the screenshot, you can see that opening the three.js animation view multiple times results in multiple instances of the canvas appearing stacked below each other.

Switching to another component resolved the duplication problem, leading me to believe it might be related to how the rendering is handled in my code. Do I need to make changes to my three.js code implementation?

If interested, you can access the full repo for download here: https://github.com/reppoper/routerthree

Here's the essential parts of my code:

App.vue
<template>
  <div id="app">
    <router-link to="/">Page1</router-link> | 
    <router-link to="/page2">Page2</router-link> 
     <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {
  }
}
</script>

Page1.vue

<template>
    <div>
        <HelloWorld/>
    </div>
</template>

<script>
import HelloWorld from "../components/HelloWorld.vue";
export default {
    components: {
        HelloWorld
    }
}
</script>

Page2.vue

<template>
  <div>
    <HelloThree />
  </div>
</template>

<script>
import HelloThree from "../components/HelloThree.vue";
export default {
  components: {
    HelloThree,
  },
};
</script>

And here are the component details:

HelloWorld.vue
    <template>
      <div class="hello">
        <h1>HELLO</h1>
      </div>
    </template>
    
    <script>
    export default {
      name: 'HelloWorld',
    }
    </script>

HelloThree.vue

<template>
  <div id="container"></div>
</template>
<script>

import * as THREE from 'three'

export default {
  name: 'HelloThree',
  data() {
    return {
      cube: null,
      renderer: null,
      scene: null,
      camera: null
    }
  },
  methods: {
    init: function() {
      this.scene = new THREE.Scene()
      this.camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      )

      this.renderer = new THREE.WebGLRenderer()
      this.renderer.setSize(window.innerWidth, window.innerHeight)

      this.container = document.getElementById("container");
      this.container.appendChild(this.renderer.domElement);

      const geometry = new THREE.BoxGeometry(1, 1, 1)
      const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
      this.cube = new THREE.Mesh(geometry, material)
      this.scene.add(this.cube)

      this.camera.position.z = 5

    },
    animate: function() {
      requestAnimationFrame(this.animate)

      this.cube.rotation.x += 0.01
      this.cube.rotation.y += 0.01

      this.renderer.render(this.scene, this.camera)
    }
  },
  mounted() {
    this.init()
    this.animate()
  }
}
</script>

router.js

import Vue from "vue";
import Router from "vue-router";
import Page1 from "./views/Page1.vue";
Vue.use(Router);

export default new Router({
    mode: "history",
    base: process.env.BASE_URL,
    routes: [
        {
            path: "/",
            name: "page1",
            component: Page1
        },
        {
            path: "/page2",
            name: "page2",
            component: () =>
                import(/* webpackChunkName: "home" */ "./views/Page2.vue")
        }
    ]
});

UPDATE I attempted to address memory leakage by adding:

  beforeDestroy() {
    this.container.destroy();
  }

Unfortunately, this resulted in an error message:

Error in beforeDestroy hook: "TypeError: this.container.destroy is not a function"

It seems like I may need to properly destroy all instances created in the component such as materials, scenes, and cameras? Any suggestions on how to resolve this issue would be greatly appreciated.

Answer №1

When working with your HelloThree component, be mindful of the fact that in the mounted hook, you are manually adding a new node to the DOM using

document.body.appendChild(this.renderer.domElement)
. Therefore, it is essential for you to remove it upon component destruction. A suitable location for this task would be within the beforeDestroy hook.

Furthermore, remember to verify if the THREE library requires any cleanup procedures to prevent potential memory leaks in your application.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The VueJS component from a third-party source is not located in the node_modules directory

Utilizing vue-cli version 3 for a fresh vuejs project (I've been dedicating ample time to learning vuejs, but this marks my initial attempt at integrating a third-party component). I'm aiming to incorporate a visually appealing grid component. Th ...

The amazingly efficient Chrome quick find feature, accessible by pressing the powerful combination of Ctrl + F, ingeniously

Currently using Google Chrome version 29.0.1547.62 m. I've employed the CSS attribute overflow set to hidden on the parent element, which renders some of my DIV elements hidden from view. Additionally, these concealed DIV elements are adjusted in pos ...

Add a fresh widget to the DOJO attachment point without overwriting

Here is some code I have: postCreate: function() { this.items.forEach(lang.hitch(this, function(item) { new SideNavigationItem({ name: item.name }, this.container); })); } This code snippet ...

Applying a dynamic translate3d transformation on the ::after element using CSS3

My current challenge involves manipulating a pseudo ::after element using translate3d If I hardcode the values, it's straightforward: div::after { ... transform: translate3d(40px, 40px, 0); } Now, I want to dynamically set the value for the ...

Having trouble with the updateOne() method in MongoDB - it's not updating my document nor displaying any errors. What could be the issue?

I'm currently facing an issue where I am attempting to update a user's document in the database with a value obtained from a calculator. However, despite not encountering any errors, the document does not seem to be updating and the page just con ...

Ways to effectively access props in Vue.js without having to pass them through a div element

Currently, I have an API call being made in the create hook of my Vue root. After that call, a component is attempting to utilize the data returned from the API. My inquiry is straightforward. Is it possible to have <stage-execs></stage-execs> ...

Issue with Vue 2: Promise does not resolve after redirecting to another page

Although I realize this question might seem like a repetition, I have been tirelessly seeking a solution without success. The issue I am facing involves a method that resolves a promise only after the window has fully loaded. Subsequently, in my mounted h ...

Creating a webpage that dynamically loads both content and video using HTML and Javascript

I designed a loading page for my website, but I could use some assistance. The loading page remains visible until the entire HTML content is loaded and then it fades out. However, I am facing an issue because I have a background video that I want to load ...

How come my HTML form keeps refreshing instead of displaying an alert after submission, even though I've included onsubmit="return false"? Additionally, it seems to be throwing an error

Why is this basic HTML and JavaScript code not functioning properly? Instead of alerting once the form is submitted, it refreshes the page and throws an error. It has also been reported to sometimes throw a CORS error when using 'module' as scri ...

Adjust the text appearance of the graph in ApexCharts

Is there a way to adjust the font size of the donut chart generated by using apexchart? You can view the image here. <template> <section> <v-card raised> <v-card-title class="blue--text">Requests Overview</v-card-ti ...

Tips for setting a unique JWT secret in next-auth for production to prevent potential issues

Is there a way to properly set a JWT secret in NextAuth.js v4 to prevent errors in production? I have followed the guidelines outlined in the documentation, but I am still encountering this warning message without any further explanation: [next-auth][warn] ...

Production environment experiences issues with Angular animations

In my MEAN stack application, I started with Sails.js. Everything was working smoothly during development, especially with angular-animate. However, once I changed the Sails environment to production, I encountered issues. Grunt is set up to concatenate a ...

Is it possible to execute asynchronous queries within a map function in Mongoose?

Currently, I am struggling to create queries using a .map function, pushing the results to an array and then returning it. The issue is that the array always ends up empty due to the asynchronous nature of the operation. Although I attempted using async/ ...

Can someone guide me on implementing Node.js clusters in my basic Express application?

— I have successfully developed a basic application that retrieves data (50 items) from a Redis DB and displays it on localhost. After running an ApacheBench test with parameters c = 100, n = 50000, I am achieving around 150 requests/sec on my aging dual ...

What is the best way to send two mongoose find queries to the correct GET route?

I am facing an issue with my app where I have two separate routes using app.get to render "/" and fetch data from two different MongoDB collections using mongoose find{} methods. I also have corresponding post routes that redirect the data entered in forms ...

Which takes precedence: the end of the script tag or the backtick?

Currently, I am working on developing a page builder widget. My goal is to save the entirety of the HTML code for the edited page to both local storage and a database. The PHP script will load the saved HTML from the database, while JavaScript will handle ...

Vue cannot compile Window.resize

Could someone please assist me in identifying the issue with this code snippet? I copied some pure HTML from a specific website. The window resize function is showing up as incorrect syntax marked in red, but I'm not sure why. Any guidance on fixing t ...

A div containing a form, with the form being visually integrated within the div

Hi everyone, this is my first post here and I've tried to search extensively before asking this question. I've attempted to use the following examples without success: jquery submit form and then show results in an existing div Form submit ...

Click to move directly to a specific section

This question may be common, but despite my research efforts, I have been unable to find a solution. I want to issue a disclaimer that I am new to javascript and jQuery. Here is an overview of what I am trying to achieve: I want two images that, when cli ...

How can I align two div buttons at the top and bottom to appear on the left and right sides?

How can I change the position of two buttons from top and bottom to left and right as shown in the second image? I am utilizing Floating Vue, so the buttons will be contained within a div. Is it feasible to adjust their position accordingly? Check out th ...