What causes the error message "Why does the 'do not alter Vuex store state outside mutation handlers' error occur?"

Although I've searched through similar topics, none of the solutions seem to fix my issue. I've been attempting to integrate Three.js with Vue3 (+Vuex). I carefully followed this tutorial: and it works perfectly on that site. However, when implementing the same code in my project, I encounter the following error:

Uncaught (in promise) Error: [vuex] do not mutate vuex store state outside mutation handlers.

I could not identify any part of the code where the state is mutated outside a mutation handler. The reason behind this error eludes me. Could it be related to Vue3 itself? It's possible that the tutorial application was built using Vue2, which might be causing compatibility issues.

Below you can find my code. I apologize if it seems lengthy, but I hope it assists in pinpointing the root cause. Additionally, I have provided a reproducible example: https://codesandbox.io/s/black-microservice-y2jo6?file=/src/components/BaseModel.vue

BaseModel.vue

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

  <script>
  import { mapMutations, mapActions } from 'vuex'

  export default {
    name: 'BaseModel',
    components: {
    },
    
    data() {
      return {
        height: 0
      };
    },
    methods: {
      ...mapMutations(["RESIZE"]),
      ...mapActions(["INIT", "ANIMATE"])
    },

    mounted() {
      this.INIT({
        width: this.$el.offsetWidth,
        width: this.$el.offsetHeight,
        el: this.$el
      })
      .then(() => {
        this.ANIMATE();
        window.addEventListener("resize", () => {
          this.RESIZE({
            width: this.$el.offsetWidth,
            height: this.$el.offsetHeight
          });
        }, true);
      });
    }
  }
  </script>

  <style scoped>
    .viewport {
      height: 100%;
      width: 100%;
    }
  </style>
  

store.js

import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js'
  import {
      Scene,
      PerspectiveCamera,
      WebGLRenderer,
      Color,
      FogExp2,
      CylinderBufferGeometry,
      MeshPhongMaterial,
      Mesh,
      DirectionalLight,
      AmbientLight,
    } from 'three'

    const state = {
        width: 0,
        height: 0,
        camera: null,
        controls: null,
        scene: null,
        renderer: null,
        pyramids: []
    };

    // Mutation functions

    const mutations = {
      ...
    };

    // Action functions

    const actions = {
      ...
    }

    export default {
      state,
      mutations,
      actions
    };
  

Answer №1

One issue at hand is that the objects being passed to initialize threejs are connected to the Vuex state, and as threejs internally modifies these objects, it triggers the warning you witnessed.

Furthermore, linking the objects to the Vuex state brings about an additional problem of generating a substantial amount of overhead to make the objects reactive. ThreeJS generates numerous internal properties, all of which then become reactive. Consequently, this rendered the app startup considerably slow.

The remedy lies in marking these objects as raw data (thereby eliminating the need for reactivity) using the markRaw() API. This way, ThreeJS can still append properties to the specified objects without establishing a reactive connection between them:

// store/main_three.js
import { markRaw } from "vue";
⋮
export default {
  ⋮
  mutations: {
    INITIALIZE_RENDERER(state, el) {
      const renderer = new WebGLRenderer(⋯);
      ⋮
      state.renderer = markRaw(renderer);
      ⋮
    },
    INITIALIZE_CAMERA(state) {
      const camera = new PerspectiveCamera(⋯);
      ⋮
      state.camera = markRaw(camera);
    },
    INITIALIZE_CONTROLS(state) {
      const controls = new TrackballControls(⋯);
      ⋮
      state.controls = markRaw(controls);
    },
    INITIALIZE_SCENE(state) {
      const scene = new Scene();
      ⋮
      state.scene = markRaw(scene);
      ⋮
      for (var i = 0; i < 500; i++) {
        var mesh = new Mesh(⋯);
        ⋮
        state.pyramids.push(markRaw(mesh));
      }
      ⋮
      // create lights
      var lightA = new DirectionalLight(0xffffff);
      ⋮
      state.scene.add(markRaw(lightA));
      var lightB = new DirectionalLight(0x002288);
      ⋮
      state.scene.add(markRaw(lightB));
      var lightC = new AmbientLight(0x222222);
      state.scene.add(markRaw(lightC));
    },
    ⋮
  },
  ⋮
};

Project Demo

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

Dealing with an empty req.body parameter in a NodeJS function for a Rest API using ExpressJs and sequelize

Looking for assistance with integrating ExpressJS and sequelize. I have a main function (fullaccount.js) that needs to invoke two functions ("accoun.js" and "people.js") receiving data in "fullaccount.js" for processing. However, while req.body is ready in ...

Verify if the nested arrays within the object consist of any empty elements

Take a look at the object below: { "params": { "time_to_diagnosis": [ { "field": "date_of_diagnosis", "value": "" }, { "field": "date_of_symptom_onset", "value": "2019-09-01" } ], "time ...

Click action: two functions, but only the first one seems to be functioning. Feeling frustrated

Here is the HTML code I am using: <td width="15%" align="center"><input name="submit" type="submit" class="button" value="Basic" tabindex="13" onclick="return submit_Click('bxbas','bxsht');" /></td> And b ...

retrieve the value obtained from a promise in an outer scope

I need a simple function that returns the name. Here's my existing code snippet: getName(entity, id) { const promise = userServices.getName(entity, id).then((data) => { return data; }); / ...

Adding a label to the surface of a sphere using Three.js

I have 300 mini orbs symbolizing human genes with their unique 3D arrangement. My challenge is to affix a label on each orb (positioned on the side) that displays essential gene details, and this label should move in sync with the orb as the viewer rotates ...

Guide to managing .glb model animations in A-FRAME using Three.js

Can someone assist me with playing a glb animation in A-FRAME using Three.js? The animation works for a second and then stops. Here is my current code: <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script> <scrip ...

Best practices for utilizing child component methods within a parent component in VUE

I am working with the ImageUpload.vue component, which is a straightforward Bootstrap modal containing a few methods. I am currently exploring the best approach to utilize one of these methods. Could it be implemented like this: const app = new Vue({ ...

Empty Canvas: Google Charts Graph Fails to Populate

I am currently using mysql, php, and javascript to display a curve chart. The issue I am facing is that the chart appears blank. google.load('visualization', '1.0', {'packages':['corechart']}); google.setOnLo ...

What specific data type is required for the following code in Angular?

const componentMapper = { input: InputComponent, button: ButtonComponent, select: SelectComponent, date: DateComponent, radiobutton: RadiobuttonComponent, checkbox: CheckboxComponent, switch: SwitchComponent, textarea: TextAreaComponent }; ...

restore the HTML element to its initial position after being moved

I am utilizing document.getElementById('Droping1').style['-webkit-transform'] = translate(0px,'+Ground+'px)'; in order to relocate an HTML element. How can I return it to its original position for reusability without t ...

What could be the source of the "Uncaught Error: write after end" error occurring in my test cases?

Below is the code I am working with: var Promise = require('bluebird'); Promise.longStackTraces(); var path = require('path'); var fs = Promise.promisifyAll(require('fs-extra')); var clone = require('nodegit').Clone ...

Retrieving user input in a JavaScript/React app

I'm currently developing a search feature for my website using Algolia. When the user types in their search term, the results are updated to show relevant matches as they go. Here is an example below of what I am working on: https://codesandbox.io/s ...

Error: Module 'mongoose' not found

I have successfully created a basic CRUD API using nodeJS, express, and mongoDB. Everything was working smoothly until I decided to enhance the security by storing password hashes instead of plain text passwords. To achieve this, I integrated the bcrypt np ...

I'm not sure how I can retrieve the pollId from a ReactJS poll

In my React code, I am fetching a poll using an API. However, I am facing an issue while working on the handleChange function for making a POST API request. The information required for the request includes PollId, userId, and answer. I am able to retrieve ...

The dropdown menu in the navigation bar is overlapping with the datatable, creating a transparency effect

Working on a website layout that features a navbar at the top and a datatable below. However, when hovering over the navbar to reveal subitems, I notice a transparency issue where the navbar overlaps with the datatable. Below is a simplified version of my ...

Skinned mesh shader with animated outline using uniform vertex displacement in Three.js

I have successfully implemented rendering borders and outlines over meshes in Three.js, a common technique in many games for highlighting objects and characters. Games like Diablo 1 and 3 use this technique extensively. Here are more details and a demo o ...

Looking for a simple method to link JSON data to an svg element through Javascript?

Looking to harness the power of SVG for a basic graph creation, but uncertain about the process of assigning JSON data dynamically using a 'for loop' to draw rectangles within SVG. Seeking guidance on setting up 1 loop to assign each value for dr ...

How can you customize the bottom and label color for Material-UI TextField when in error or when in focus?

I need to customize the color of my Material UI TextField component for the following states: error focused Currently, I am using version 3.8.1 of @material-ui/core and working with the <TextField /> component. I would like to achieve this withou ...

What is the best way to assign a distinct index value to each object in an array

When I use the function below to add an index to each array object, all IDs end up with the same value when I check console.log: var foo = [...this.props.articleList]; foo.forEach(function(row, index) { row.id = index+1; }); console.log(foo); My des ...

React testing with Mocha experiencing an Invariant violation

Currently, I am in the process of setting up a React project using Electron. Lately, I have been experimenting with configuring Mocha as my test framework. Everything seems to be working fine when I run: "test": "mocha -w --require babel-core/register ...