Switching between two identical components can be easily achieved with VueJS

Assume I have a file named foo.vue, which I import into the parent component as components called a and b, and they are displayed based on a variable called show.

When switching between components a and b in the parent without setting show = null, various child state errors occur.

To resolve this issue, I tried setting show to null before assigning it to the respective Vue component like this:

this.show = null
this.show = a // or b

However, this approach did not work as expected. The component ended up retaining the state of the previous one, even for props that were not updated.

I managed to make it work by using a timeout:

toggle(show){
   this.show = null
   let that = this
   setTimeout(() => {
      that.show = show
   }, 200)
 }

Is there a more elegant solution available? The current method does not seem very clean to me.

It seems that what happens within the child component should not affect the switch triggered by the parent; it should start fresh and rebuild. However, in my case, this does not happen. Are there any factors causing this issue?

Does setting to null trigger a hard refresh somehow?

My child component is complex with AJAX calls to retrieve a list but nothing extraordinary.

Parent Component Code:

<template>
<div id="userAreaEventWrapper">
    <div class="userarea-submenu">
        <div v-on:click="toggle(comps.eventForm)" class='button-base-out'>
            <div :class="isSelected(comps.eventForm)">
                New Event
            </div>
        </div>
        <div v-on:click="toggle(comps.events)" class='button-base-out'>
            <div :class="isSelected(comps.events)">
                My Events
            </div>
        </div>
      <div v-on:click="toggle(comps.eventsAttending)" class='button-base-out'>
        <div :class="isSelected(comps.eventsAttending)">
          Attending
        </div>
      </div>
    </div>
    <EventForm v-if="show === comps.eventForm" @created="toggle(comps.events)" :mode="'create'"></EventForm>
    <Events ref="events" :mode="currentMode" v-if="show === comps.events" @noResults="toggle(comps.eventForm)" :attending="false"></Events>
    <AttendingEvents ref="attending" :mode="'home'" v-if="show === comps.eventsAttending" :attending="true"></AttendingEvents>
</div>
</template>

<script>
const EventForm = () => import( './event-form.vue')
const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')

export default {
    name: "UserEventComponent",
    components:{
        EventForm,
        Events,
        AttendingEvents
    },
    data(){
        return{
            comps:{
              eventForm:1,
              events:2,
              eventsAttending:3
            },
            show: 2,
            currentMode:'user',
        }
    },
    methods: {
        toggle(show){
          this.show = null
          let that = this
          setTimeout(() => {
            that.show = show
          }, 200)
        },
        isSelected(n){
          return n === this.show ? 'button-base-in button-base-in-hover' : 'button-base-in'
        },

    },
}
 </script>

Child Component Code:

Fetching API data in mounted():

  mounted() {
    this.currentMode = this.mode
    if(this.resumeData && this.resumeData.slug){
       this.selectedSlug = this.resumeData.slug
    } else {
       this.resume(this.resumeData)
       this.getEvents()
    }
   }

Answer №1

This section serves little purpose:

const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')

The main advantage of JavaScript modules (including ES modules) is that they are only evaluated once upon initial import, meaning import( './events.vue') will point to the same component. This provides clarity on how a component is being utilized under one name.

When an update occurs with show, there will be one instance of the events component within the component hierarchy, avoiding remounting and simply receiving new props defined in <Events> and <AttendingEvents> respectively.

To differentiate between sibling instances of the same component, a key should be used:

<Events ref="events" key="events" ... ></Events>
<Events ref="attending" key="attending" ... ></Events>

While commonly used with v-for, this practice can also be applied to directives like v-if that impact the component hierarchy.

Answer №2

It seems like the issue you're facing stems from making an API call to modify data in the component within the mounted hook.

When you switch components without using a timeout, the child component is already rendered and active, but it changes props. By introducing a timeout and updating this.show = null before rendering, the component won't be displayed initially. Subsequently, when switching to the correct component within the timeout, the component will re-render which triggers the mounted hook.

To tackle this issue effectively, consider implementing a watcher within the child component that monitors changes for each instance of the component (e.g., through an ID). This watcher can then facilitate API calls based on those changes.

For example, include an 'id' prop and watch it as follows:

props: {
  id: {
    type: Number,
    default: 0
  }
},
watchers: {
  id() {
     this.currentMode = this.mode
    if(this.resumeData && this.resumeData.slug){
       this.selectedSlug = this.resumeData.slug
    } else {
       this.resume(this.resumeData)
       this.getEvents()
    }
  },
  immediate: true
}

By setting immediate: true, the watcher will trigger upon mounting the component, eliminating the need to call it within the mounted hook again.

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

Upon utilizing JSON.parse in Express, an unexpected token < in JSON was encountered at position 0 while attempting a client side fetch POST

I'm trying to send a basic object through a fetch request to my express server, but I keep encountering an error when attempting to log it. Currently, if I log req.body (with the header 'Content-Type': 'application/x-www-form-urlencode ...

Modify the class name of the clicked button and another button when a button is clicked in ReactJs

I have a React component that displays two buttons. When the user clicks on the left button, it should change the class of both buttons and render the ListView component. Similarly, when the user clicks on the right button, it should change the class of bo ...

How can I prevent event propagation in Vuetify's v-switch component?

Currently, I am working with Vuetify and have incorporated the use of v-data-table. Whenever I click on a row within this data table, a corresponding dialog box represented by v-dialog should open. Additionally, each row contains a v-switch element. Howeve ...

In Node.js, it is essential to use req.session.save() to ensure that sessions are properly saved

While developing a website with Node.js, Express, and Redis for session management, I noticed an issue where my session variable (isLoggedIn) wasn't being saved after refreshing the page. Strangely, calling req.session.save() after setting the variabl ...

Tips for accessing an element using a specific identifier with the variable $key

PHP //This is the HTML code for quantity <p>Qty : <input type="number" value="" name="qty<?php echo $key ?> onChange="findTotal()"/> JS function function findTotal() { var arr = document.getElementsByName('qty'); // Calc ...

Add multiple checkboxes in a dropdown menu to save in a MySQL database

I have a register.php and I'm trying to insert the data into users table. The problem I have is with "languages" field - I've created a dropdown list with multiple checkboxs. I want the user of course to be able to insert to his profile more tha ...

Removing redundant names from an array using Typescript

My task involves retrieving a list of names from an API, but there are many duplicates that need to be filtered out. However, when I attempt to execute the removeDuplicateNames function, it simply returns an empty array. const axios = require('axios&a ...

Showing recurring HTML elements with conditional content

I am displaying multiple bootstrap badges in a table column with different colors based on the values. Each badge has a unique class and style name to differentiate the colors. I feel like there is a lot of repetition in my HTML code. Is there a way for me ...

How can I ensure that my user responses are case-insensitive?

Currently, I'm facing a roadblock in my coding journey. I am trying to modify my code so that user responses are not case sensitive when compared for correctness. Can anyone offer some advice on how to achieve this? Check out the code snippet below: ...

How to designate a default selection value using local array data source in Select2.js version 4.0?

If I am using the select2.js v4 plugin with a local array data source, how can I set the default selected value? For instance, consider the following code: var data_names = [{ id: 0, text: "Henri", }, { id: 1, text: "John", }, { id: 2, text: ...

The ActionController is encountering an UnknownFormat error when trying to respond to AJAX requests with js using

I've been scouring the internet for information on this topic, but I'm having trouble understanding how AJAX works with Rails. I've gone through the documentation multiple times and it's just not clicking for me. From what I gather, AJ ...

To retrieve a property in Vue, you can use either the "this" keyword

Exploring Vue for the first time and navigating through accessing viewmodel data has me puzzled. When should I utilize this.property versus vm.$data.property. In this scenario with a table where I can select rows, there are methods in place to select all ...

Encountering a "Duplicate identifier error" when transitioning TypeScript code to JavaScript

I'm currently using VSCode for working with TypeScript, and I've encountered an issue while compiling to JavaScript. The problem arises when the IDE notifies me that certain elements - like classes or variables - are duplicates. This duplication ...

Refresh the page with cleared cache using window.location.reload

Is there a way to reload a page using JavaScript and still clear the cache, ensuring that the refreshed page shows the latest content from the server? It seems that other browsers are not displaying the most up-to-date versions of the content. Anyone have ...

Modify input value using jQuery upon moving to the next step

When you type into an input[text] and press the tab button, it automatically moves to the next input. If you fill out all the inputs and then want to re-fill them, the values will be highlighted in blue. However, I wanted to achieve this without having to ...

In the world of GramJS, Connection is designed to be a class, not just another instance

When attempting to initialize a connection to Telegram using the GramJS library in my service, I encountered an error: [2024-04-19 15:10:02] (node:11888) UnhandledPromiseRejectionWarning: Error: Connection should be a class not an instance at new Teleg ...

Send the chosen item from the <b-form-select> element to the parent component through props

Using Vue.js, I have successfully created a form where all input fields pass their values except for the <b-form-select> element. How can I pass the value of the selected option in <b-form-select> to the parent component? Child Component: < ...

Image not showing up on HTML page following navigation integration

Having trouble with my responsive website setup - the background image for ".hero-image" isn't showing up after adding the navigation. Google Chrome console is throwing a "Failed to load resource: the server responded with a status of 404 (Not Found)" ...

Error message "env: '/bin/flask': No such file or directory" pops up while executing the command "npm run start-backend"

Currently on the hunt for a super basic website template that combines Flask and React. I've been using this repository and carefully following the installation steps laid out https://github.com/Faruqt/React-Flask Working on Windows 10 using git Bas ...

Distinctive titles for JavaScript constructors/prototypes compared to classes

When working with JavaScript ES6, classes allow us to write code like this: class RectangularShape { constructor(height, width) { this.height = height; this.width = width; } getArea() { return this.height * this.width } static some ...