Vue: child component not updating despite receiving props from parent component

I'm facing an issue related to communication between parent and child components in Vue. The problem arises when I navigate to a component, triggering an AJAX call to fetch data from the server. Despite receiving the data successfully, the parent component fails to pass it down to the child components via props. Interestingly, the child components only display the props data after I make changes in my code editor.

Here's the code snippet for my parent component:

<template>
  <div id="single-product-container">
    <product-header :name="singleProductName" :details="singleProductDetail" />
    <product-spec :spec="singleProductSpec" />
  </div>
</template>

<script>
import SingleProductHeader from '@/pages/SingleProductPage/single-product-header'
import SingleProductSpec from '@/pages/SingleProductPage/single-product-spec'
import singleProductApi from '@/api/product.api'

export default {
  data () {
    return {
      singleProductData: null,
      singleProductDetail: [],
      singleProductName: '',
      singleProductSpec: null
    }
  },
  methods: {
    getAllSingleProductDetail () {
      const productName = this.$route.params.product
      const location = this.location || 'jakarta'
      let vehicleType = null
      const path = this.$route.fullPath
      let self = this
      if (path.includes('motorcycle')) {
        vehicleType = 'motorcycle'
      } else if (path.includes('car')) {
        vehicleType = 'car'
      }
      singleProductApi.getSingleProductRequest(location, productName, vehicleType)
        .then(singleProductResponse => {
          console.log(singleProductResponse)
          let specObj = singleProductResponse.specification
          self.singleProductDetail = singleProductResponse.detail
          self.singleProductName = singleProductResponse.product_name
          self.singleProductSpec = specObj
          self.singleProductData = singleProductResponse
        })
        .catch(error => {
          throw error
        })
    }
  },
  mounted () {
    document.title = this.$route.params.product
  },
  created () {
     this.getAllSingleProductDetail()
  },
  components: {
    'product-header': SingleProductHeader,
    'product-spec': SingleProductSpec
  }
}
</script>

Next, here is the single-product-spec component that encounters issues with loading the props data:

<template>
  <div id="product-spec">
    <div class="product-spec-title">
      Spesifikasi
    </div>
    <div class="produk-laris-wrapper">
      ...
    </div>
  </div>
</template>

<script>
export default {
  props: {
    location: String,
    spec: Object
  },
  data () {
    ...
  },
  methods: {
    openSpaceTab (evt, tab) {
      ...
    }
  },
  created () {
    this.mesinData = this.spec.mesin
    this.rangkaData = this.spec.rangka
    this.dimensiData = this.spec.dimensi
    this.kapasitasData = this.spec.kapasitas
    this.kelistrikanData = this.spec.kelistrikan
  }
}
</script>

The issue lies within my single-product-spec component which fails to load the props data unless I modify the code in my text editor. This unusual behavior was discovered during debugging sessions, where altering the code in the single-product-spec component triggers the loading of props data. Without these modifications, the props data remains unloaded regardless of the waiting time.

Answer №1

Let's walk through the sequence of events:

  1. The parent component is initialized, triggering the created hook and starting the data retrieval from the server.
  2. The parent component is rendered, generating the child components. The spec prop value will be null initially since the data is not loaded yet and singleProductSpec is still null.
  3. The created hook for single-product-spec executes. If this.spec is null, it might cause an error, although it wasn't mentioned in the question.
  4. Eventually, the data retrieval process completes, updating the value of singleProductSpec. This triggers a re-rendering of the parent component where the updated spec prop is passed to single-product-spec. The existing instance of single-product-spec is used without creating a new one.
  5. Upon re-rendering the parent component, the new value of singleProductSpec is transferred as the spec prop to single-product-spec. No new instance is created, saving resources.

After this point, nothing further occurs. The created hook of single-product-spec does not run again because it was already created.

When you modify the source code of the child component, it triggers a hot-reload of that component. This can result in the recreation of the child component while keeping the parent component unchanged. Since the parent already has the server-loaded data, the newly created child receives the fully-populated spec value. This setup allows the child to access this data within its created hook.

Various solutions can address these issues.

One approach is to delay creating the single-product-spec until the data is available:

<product-spec v-if="singleProductSpec" :spec="singleProductSpec" />

This method avoids instantiating the component during the initial render, ensuring that when the child's created hook runs, it has access to the required data.

Another option involves using a key to pair up components across renders. Vue will replace the old child component with a new one if the key changes. However, this may not be suitable if handling a case where the child component receives a null spec.

A third possibility is employing a watch in the child component to track changes in the spec value and update local data properties accordingly. While useful in some scenarios, heavy reliance on watchers could indicate design weaknesses.

Furthermore, there are additional issues in your code...

  1. The practice of copying values from props to local data might be unnecessary. Directly accessing the prop or using a computed property could simplify your code. Consider revisiting the use of props based on Vue's one-way data flow principle.
  2. Optimize the structure by utilizing an array of objects instead of duplicating logic for each tab. Each object should contain all necessary details for a tab.
  3. Consolidate similar data representation like mesinActive and mesinTab into a single entity within the data. Consider using CSS classes for styling differentiation based on the active state.
  4. Rethink the data structure for managing tabs selection. Rather than using multiple boolean values, maintain a single property identifying the current tab (like an index or unique identifier).
  5. Eliminate the need for let self = this when using arrow functions, as they preserve the correct reference to this automatically.

An adequately structured implementation of the single-product-spec should significantly reduce complexity. Streamline your codebase by leveraging appropriate data structures, potentially reducing overall code volume by 80%. With optimized data storage, complex methods like openSpaceTab could become succinct, enhancing readability.

Update:

Here's a revised version of your component considering points 1-4 outlined in the 'other problems' section of my response.

// Your modified Vue component

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

When is it necessary to escape special characters? (Using jQuery Selectors)

As per the documentation provided by jQuery, it is essential to escape metacharacters that appear in selector strings when used as a literal. However, I found limited specific examples on when to escape selectors. So, the question arises: When should I esc ...

Incorporating React into a non-React website

I am currently working on a project where the server renders all views using the Twig template engine. Therefore, I tend to write all my scripts within the .twig templates. Take, for instance, the aside-buttons.twig template: <div class="aside-butto ...

Using JavaScript to toggle the display of a label element

Greetings everyone! I recently posted a question on this thread about replacing input with javascript, but ended up abandoning that idea. Instead, I decided to explore a different approach... I made the background of my password field transparent and posi ...

Using select2 scss from the node_modules folder

Looking for help with importing select2 scss from node_modules. I successfully installed the select2 by running the command: npm install select2 which created a select2 folder in the node_modules directory. Can anyone guide me on how to import the css f ...

Retrieve the most recent tweet from a user's timeline using the twit npm package

I need help setting up a discord bot to send notifications for new tweets. Currently, I've implemented T.stream('statuses/filter', { follow : ['798934987978510337'] });, but it's also displaying mentions. Is there a way to o ...

Numerous data inputs to manage with just a single submit button in redux-saga

I am facing an issue with handling multiple inputs and saving the data using a single button in my React component. Here is the method I have implemented: handleClick(e) { e.preventDefault(); this.props.newEmail ? this.props.onSaveNewEmail(this.p ...

Tips for merging Next.js configuration settings

My current configuration settings are as follows: module.exports = { images: { domains: [ "ticket-t01.s3.eu-central-1.amazonaws.com", "media.istockphoto.com", ], deviceSizes: [320, 375, 450, 540, 640, 750, 828, ...

Converting Javascript game information into PHP

Once the player loses, I need their score to be updated in the database using PHP. There is a separate JavaScript class that runs the game, utilizing setInterval to check the index.php function and update the database if the player loses. However, the issu ...

Customizing next.js _error page with i18n localization

Looking to create a customized error page for my Next.js project. I've been using the getServerSideProps method to localize my other pages, but I'm running into issues with translating strings on the _error page. I attempted to use the getStaticP ...

Highcharts - resolving cross-browser e.Offset discrepancies in mouse event detection on charts

I need to determine if the mouseup event is inside the chart and display the coordinates of the point. The code works in Chrome but not in Firefox due to the lack of the event.offset property. jQuery(chart.container).mouseup(function (event) { eoff ...

Challenges encountered while working with OpenWeather API

I created a weather prediction web application using p5.js. It functions perfectly on my local server. However, I keep encountering this issue on the GitHub page: Mixed Content: The page at '' was loaded over HTTPS, but requested an insecure ...

Adjust index starting from 0 in JavaScript

Struggling with setting a consistently unique index that increments by one. Here is an example of my array: const originalArr = [ { name: 'first parent array', childArray: [ { name: '1 / first child' }, ...

Create a downloadable document in AngularJS containing specific data

I need to collect user input values such as name, address, and phone number. Once the values are entered, I want to dynamically generate a downloadable MS Word document file on button click using AngularJS. How can I accomplish this task? Is it feasible t ...

AngularJS framework may encounter an issue where changes in $scope data do not reflect in the view

I have noticed that when I reload the data using my function, the view does not change. After some research, I found that adding $scope.$apply() should solve this issue. However, I am encountering an error when trying to implement this solution. https://d ...

Having trouble displaying results in Vue.js after making an API request?

I am facing challenges in displaying the results using vue.js. The data from my API (ASP.NET CORE) is being retrieved successfully, as shown in my vue dev tools on Google Chrome. However, I am encountering difficulties in rendering the results on the brows ...

Angular's use of ES6 generator functions allows for easier management of

Recently, I have integrated generators into my Angular project. Here is how I have implemented it so far: function loadPosts(skip) { return $rootScope.spawn(function *() { try { let promise = yield User.findAll(); $time ...

Tips for utilizing multiple ngFor directives for property binding within a single directive

After implementing the ng-drag and drop npm module with the draggable directive, I encountered an issue while trying to display a list of items from a 2D array using li elements. Since multiple ngFor's are not allowed in Angular, I needed to come up w ...

Utilizing Vuejs within Laravel's blade templates

Hey there, I'm looking to create a dormitory management system using Laravel and Vue.js. I need help figuring out how to display my data using a Vue component instead of the "welcome.blade.php" file in Laravel. I am utilizing API routes for this proje ...

Tips for showcasing the contents of a file on a website

Greetings! I am a newcomer to the world of web development and I am seeking a method to showcase file content on a webpage. Presently, I have succeeded in loading text file content and displaying it in a large text box. However, I am now interested in di ...

Display HTML code within a data attribute

I have a function that modifies an element from OpenLayers. In the official documentation, it mentions that the property label accepts either HTML or a string. methods: { onUpdatePosition (coordinate) { this.deviceCoordinate = coordinat ...