6

The Task

I'm working on a marketplace of products. Each product has an ID and a bunch of information associated with each product.

There is a concept of packages of the products, which is simply a product that is a bundle of other products.

Within the GET PACKAGES response, there is an array of IDs which relate to the products inside this package. Else where on the page, I request a list of products, so I have the data I need already, I just need to connect the two data sets.

The task involves showing the packages in the UI, along with a description of each product (which is in the other response of GET PRODUCTS) which is connected by IDs between the two data sets.

Description of Setup

I have a parent component, which calls GET PRODUCTS and GET PACKAGES.

I pass the package down to a reusable Vue component to display basic information on that package in the UI. As well as this, I pass down ALL the products down to the component also, so that we can get the right product descriptions to display in the preview of the package UI.

The Problem

When passing down the list of products into the child component, I can console log the entire array of products perfectly fine, however the second I try to loop through them (either via MAP or FOREACH) nothing happens. No console log inside the loop; it's like the loop doesn't even run.

The Parent Component Code

<package 
    v-for="package in packages" 
    :key="package.id"
    :packages="package"
    :products="products"
></package>

// I get both sets of data in beforeOnMount and push it to the below variables
const packages = reactive<Array<Package>>([]);
const products = reactive<Array<Product>>([]);

The Child Component Code

props: {
    packages: Object as () => Package,
    products: Object as () => Array<Product>
}

setup(props) {
    const uiPackages= reactive<Array<IPackageDetails>>([]);
    const productData = props.products;

    // This console log's a Proxy, with the handler containing an array of objects perfectly fine.
    console.log(productData);

    if (productData) {

        // This console log's undefined
        console.log(productData[0]);

        productData.forEach((product) => {

            // This does NOTHING in console!
            console.log(product)
        }
    }
}

Console Log of the productData in the child component

Products with data blurred out due to NDA

Jamie Bohanna
  • 530
  • 1
  • 8
  • 26

1 Answers1

6

When the child component initializes, the products prop is still an empty array. The reason you see data in the console is because the console updates itself when you click it, and by that time the parent's async request has completed.

This only happens with references, so you couldn't see the individual array item product[0] which has no reference when you log it.

Use a watch (or watchEffect) on the prop to wait for the items to be fetched:

setup(props) {
  const productData = props.products;

  watch(() => productData.length, () => {
    productData.forEach((item) => {
      console.log(item)
    })
  })
}

Alternatively, you could use a v-if in the parent:

<template v-if="packages.length && products.length">
  <package 
    v-for="package in packages" 
    :key="package.id"
    :packages="package"
    :products="products"
  ></package>
</template>
Dan
  • 59,490
  • 13
  • 101
  • 110
  • Fantastic - Would you assume the fact that I don't need a watch method elsewhere in the app is just the fact that the API returns the response faster than the page needs the data? – Jamie Bohanna Mar 08 '21 at 12:47
  • Also could we avoid a watch method by wrapping the child component in a v-if at the parent level to prevent the component from loading until the data is ready? – Jamie Bohanna Mar 08 '21 at 12:47
  • 1
    1) If by elsewhere you mean a template: the template reactively updates, so you never noticed it had no length for a moment (and it never tries to access elements). 2) Yes, I prefer the `v-if` over extra code in every child. Though sometimes it can be nice to show the child with a loading graphic, depending. – Dan Mar 08 '21 at 12:56
  • 1
    I added a `v-if` snippet to the answer. – Dan Mar 08 '21 at 12:57