Issue with Vue/Nuxt 3: Unable to modify properties of null when setting 'textContent'

I am currently facing an issue with a function that is designed to switch words every few seconds. The functionality itself is working fine, but I keep encountering the following error intermittently in the VSC console:

TypeError: Cannot set properties of null (setting 'textContent') at Timeout._onTimeout (.../components/home/Hero.vue:36:28) at listOnTimeout (node:internal/timers:564:17)

It's puzzling because when I console.log word.value, I can see that the element is being accessed successfully. This indicates that the function is indeed changing the words as intended, yet the error persists. I find this discrepancy confusing and am unsure how to troubleshoot it effectively. It's worth noting that the error only surfaces in the VSC console, not in Google Chrome's console.

<span ref="word"></span>
onMounted(() => {
  randomizeText()
  wordChanger
})

onBeforeRouteLeave(() => {
  clearTimeout(wordChanger)
})

const wordChanger = setInterval(randomizeText, 4000)

const word = ref(null)
const words = reactive(['Word-1', 'Word-2'])
let i = 0

function randomizeText() {
  i = randomNum(i, words.length)
  const newWord = words[i]

  setTimeout(() => {
    word.value.textContent = newWord
  }, 200) // time to allow opacity to hit 0 before changing word
}

function randomNum(num, max) {
  let j = Math.floor(Math.random() * max)

  // ensure diff num every time
  if (num === j) {
    return randomNum(i, max)
  } else {
    return j
  }
}

Answer №1

Instead of utilizing const word = ref(null) as refs, you can directly reference it as the constant word within your template, and it will still function as expected.

<template>
  <div>
    <span>{{ word }}</span>
  </div>
</template>

When inside the setTimeout function, make sure to change word.value.textContent = newWord to word.value = newWord.

Here are the updated codes that have been tested and proven to work seamlessly.

<script setup lang="ts">
onMounted(() => {
  randomizeText()
  wordChanger
})

onBeforeRouteLeave(() => {
  clearTimeout(wordChanger)
})

const wordChanger = setInterval(randomizeText, 4000)

const word = ref('') // UPDATED
const words = reactive(['Word-1', 'Word-2'])
let i = 0

function randomizeText() {
  i = randomNum(i, words.length)
  const newWord = words[i]

  setTimeout(() => {
    word.value = newWord // UPDATED
  }, 200) // allowing opacity to reach 0 before changing word
}

function randomNum(num, max) {
  let j = Math.floor(Math.random() * max)

  // ensuring a different number each time
  if (num === j) {
    return randomNum(i, max)
  } else {
    return j
  }
}
</script>
<template>
  <div>
    <span>{{ word }}</span>
  </div>
</template>

I trust this explanation aids your understanding.

Answer №2

It seems like the issue here is related to timing, where the element may not be fully mounted while it is being manipulated by the code.

An alternative approach to directly setting the textContent property is to utilize the v-html directive and update the referenced variable (ref) instead. Additionally, you can initialize the interval within the onMounted() hook.

import {onMounted, reactive, ref} from "vue";
import {onBeforeRouteLeave} from "vue-router";

let wordChanger;

onMounted(() => {
    randomizeText()
    wordChanger = setInterval(randomizeText, 4000);
})

onBeforeRouteLeave(() => {
    clearTimeout(wordChanger)
})

let word = ref('Hello')
const words = reactive(['Word-1', 'Word-2'])
let i = 0

function randomizeText() {
    i = randomNum(i, words.length)
    const newWord = words[i]

    setTimeout(() => {
        word.value = newWord
    }, 200) // time to allow opacity to hit 0 before changing word
}

function randomNum(num, max) {
    let j = Math.floor(Math.random() * max)

    // ensure different number every time
    if (num === j) {
        return randomNum(i, max)
    } else {
        return j
    }
}
<span v-html="word"></span>

Answer №3

You may be misusing the ref 'word' and here are some other details I have highlighted:- note: I have added comments to the lines that I have modified for better clarity

setup() {
    

    const word = ref(null);
    const words = reactive(['Word-1', 'Word-2']);

    function randomizeText(i) {
      const p = randomNum(i, words.length);
      const newWord = words[p];

      setTimeout(() => {
        word.value = newWord;
      }, 200); // giving time for opacity to reach 0 before changing word
    }

    function randomNum(num, max) {
      let j = Math.floor(Math.random() * max);

      // ensuring different number every time
      if (num === j) {
        // note that I have used num instead of i here as well
        return randomNum(num, max);
      } else {
        return j;
      }
    }
    
    const wordChanger = setInterval(randomizeText, 4000);
    
    onMounted(() => {
      randomizeText(0); // starting with 0
      // wordChanger; // no need to use this here
    });

    onBeforeRouteLeave(() => {
      clearTimeout(wordChanger);
    });

    return {
      word,
    };
  },
<span>{{ word }}</span>

Check out a demo here:- https://stackblitz.com/edit/vue-rap7bb?file=src/components/HelloWorld.vue

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

Typescript: Determine when a property should be included depending on the value of another property

Having some difficulty with Typescript and React. Specifically, I am trying to enforce a type requirement for the interface Car where the property colorId is only required if the carColor is set to 'blue'. Otherwise, it should not be included in ...

Is it normal for my sweelart2 to consistently be positioned behind my v-dialog component in Vuetify 3?

Why does my sweetalert2 always appear behind my v-dialog in Vuetify3? Can anyone assist me with resolving this issue? I have tried various alternatives for sweetalert2 but have not found a solution yet. Whenever I use sweetalert with v-dialog, the sweetal ...

What is the best way to hide the jQuery modal I created?

Hello everyone! Currently, I am working on coding a simple JS modal that can be opened and closed smoothly. The issue I am facing is related to adding a click function to (.black-overlay) in order to fade out everything and close the modal. <div class ...

Navigational packages for React applications

As I make decisions for my React project, I am considering which routing library to choose. Are there any alternatives to "react-router," "ui-router," and "react-navigation" that you would recommend? ...

Issue with the statement not being recognized for counting the space bar

I created a counter but I'm having trouble incorporating if statements For example: if (hits == 1) {alert("hello world1")} if (hits == 2) {alert("hello world2")} if (hits == 3) {alert("hello world3")} if (hits == 4) {alert("hello world4")} This is t ...

The issue of AngularJS directive failing to update controller variable

After conducting an extensive search on both Google and Stack Overflow, I was unable to find a solution to the issue at hand. So, moving forward, here is the problem I am facing: I have created a directive that is intended to retrieve data selected in a ...

Utilizing Vuex data dynamically within a v-for loop

Can Vuex data be accessed dynamically in a v-for loop within a template? I attempted to access it using the $data variable in the template but without success: <template> <div v-for="(item, index) in items"> {{item.id}}: {{$data[i ...

Developing JavaScript code for preventing blocking

Managing a large number of file requests from a tiny server has been a challenge for me. With approximately 100 files to fetch, my current approach using JavaScript's forEach loop is causing the server to crash due to the heavy load. links.forEach ...

Discover the nodes with the highest connections in a D3 Force Graph

As I explore the functionalities of a D3 Force Directed Graph with zoom and pan features, I encounter an issue due to my limited knowledge of d3.js. Is there a way to estimate the number of links for each node in this scenario? I am currently at a loss on ...

Experiencing difficulties while attempting to organize an array?

// const first = data.groups_with_selected[7]; // const second = data.groups_with_selected[20]; // data.groups_with_selected.splice(2, 0, first, second); // data.groups_with_selected.splice(9, 1) // data.groups_with_selected ...

Is there a way to retrieve the intersection point (Vector3) of the intersectObjects?

I need assistance in finding the point where a ray cast from 'child' intersects with a mesh (child2) using Raycaster: var raycaster = new THREE.Raycaster(); var meshList = []; meshList.push(child2); for (var i = 0; i < child.geometry.vertices ...

Utilize linear gradient effect in editing images and then convert them to base64 format using React

I have been working with the "canvas" library to edit an image via URL using linear-gradient, employing various methods. However, I am facing challenges in achieving the desired results so far. The methods I tried using canvas do not seem to work seamless ...

What is the best way to retrieve the value from a textbox on the client side and then utilize it to generate

I am currently utilizing jQuery for my modal dialogs. My goal is to open a model dialog from one page and send some additional query strings to the modal dialog page. Is there a way to achieve something like this? <asp:HyperLink ID="hypClientSearch" ru ...

Cease the use of jQuery animations

My JavaScript code snippet looks like this: $.get("/<page>.php", "userid='.$userid.'&"+status, function(data){ $("#status").show("fast").html(data).delay(4000).hide("fast"); }); On a page with multiple links triggering thi ...

Limiting the zoom in three.js to prevent object distortion caused by the camera

I'm currently in the process of developing a three.js application where I have successfully loaded my STL objects and incorporated 'OrbitControls'. However, I am encountering an issue when attempting to zoom using the middle scroll button on ...

Is there a Node template engine similar to EJS that seamlessly integrates with HTML templates?

Is there a template engine for NodeJS similar to EJS that doesn't alter the original HTML template structure with its use of parentheses? In EJS, one might utilize the following code snippet to embed specific data into the HTML template: <script& ...

String variable representing the name of a React element

As I was reviewing the source code of a React UI library, I stumbled upon an interesting code pattern that I will simplify here: function Test() { let Button = "button"; // ... return <Button>Click me</Button>; } I'm curious about ...

The installation of plugins in Vue has hit a snag

I attempted to install the Vue Router and Vuex plugins, but my terminal seems to be frozen at that point. My Vue version is current and I've even tried re-installing it, however the issue persists. I also gave the Vue UI installation a shot, but enco ...

Issues with Vue.js v-for functionality causing inconsistencies

Just delving into the world of Vue.js and encountering a hitch. I've been following a tutorial on Laracasts, but my v-for directive seems to be causing some trouble. Here's the HTML: <div id="root"> <ul> <li v-for="name in ...

Mastering NodeJS Promises: Efficiently Handling Multiple http.get Requests

I have recently started learning about NodeJS and Promise functionality, so please be patient with me if this question seems uninformed. My goal is to first retrieve a database of records and then verify that the links associated with these records return ...