0

I want to load some content of a vue component based on a given argument. Here is some code to illustrate:

ParentComponent.vue

<Suspense>
<div class="row g-0">
  <div class="col-md-3">
    <ChildComponent json-url="some/url/to/json/data" />
  </div>
  <div class="col-md-3">
    <ChildComponent json-url="some/url/to/json/data" />
  </div>
  <div class="col-md-3">
    <ChildComponent json-url="some/url/to/json/data" />
  </div>
  <div class="col-md-3">
    <ChildComponent json-url="some/url/to/json/data" />
  </div>
</div>

<template #fallback>
  <p>Loading...</p>
</template>

ChildComponent.vue

<template>
 <!-- some content based on the loaded json data -->
</template>

<script setup>
  import { ref, onMounted} from 'vue';
  

  defineProps({jsonUrl: {
    type: String,
    default: ""
  }})
  const images = ref(null);
  const thumbnail = ref(null);
  const title = ref("");
  const description = ref("");

  onMounted(async () => {
    try {
      const response = await fetch(new URL(jsonUrl, import.meta.url).href);
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      var jsonData = await response.json();

      images = jsonData["images"];
      thumbnail = jsonData["thumbnail"];
      title = jsonData["title"];
      description = jsonData["description"];
      console.log(thumbnail);
      
    } catch (error) {
      console.error('Error fetching the JSON file:', error);
    }
  });

</script>

The problem is that jsonUrl does not seem to be available during the onMounted() callback. Naming and everything should work, since if I simply put <p>{{json}}</p> into the template it shows the urls correctly.

I have searched around a bit, but it seems the property should be available? For example, this post answer shows pretty much the same approach (only difference being the usage of typescript). How can I correctly load and initialize my content based on the json data within my child component here?

5
  • Probably because of this? stackoverflow.com/a/44319825/8816585
    – kissu
    Commented Jun 19 at 9:11
  • @kissu thanks for the link. This seems plausible, let me check. In the meanwhile, is there another callback function I can/should use for this kind of usecase? Commented Jun 19 at 9:15
  • 1
    Could maybe use Suspense to fine a fine-grain managment of the flow of your calls: vuejs.org/guide/built-ins/suspense.html#suspense I don't remember all the ways to solve this issue but there are a few.
    – kissu
    Commented Jun 19 at 9:17
  • And yes - simple console.log() shows that children are called before the parents. Commented Jun 19 at 9:17
  • 1
    As said, use suspense for this and move async code to setup body. thumbnail = - this is a mistake, you lose reactivity by reassigning refs. "jsonUrl does not seem to be available" - how did you check? "new URL(jsonUrl, import.meta.url)" - this looks suspicious as you seem to try to fetch something from src/ , this is not how it works Commented Jun 19 at 9:31

1 Answer 1

2

When using setup, you have to define the props variable:

const props = defineProps({jsonUrl: {
  type: String,
  default: ""
}})

Then use props.jsonUrl to access the prop. This should allow you to access the prop inside of onMounted

8
  • Sorry, but my code already contains defineProps, so the issue lies elsewhere (according to the comments above most likely lifecycle stuff) Commented Jun 19 at 9:24
  • I meant you don't set the props to a variable in your code, you only have to add the const props = part before the defineProps(...
    – Sjoertjuh
    Commented Jun 19 at 9:26
  • Ah ok, in any case it doesn't really make a difference. While I can't find it in the docs atm, I have read somewhere that this shouldn't be needed and is assigned automatically. But thanks for the suggestion anyway :) Commented Jun 19 at 9:31
  • Actually, I was wrong. As pointed out your actual answer using props.jsonUrl works immediately. So your approach works (combined with the fact pointed out by the comments above, that I can simply put everything into an async setup body). Now I am just curious what happens behind the scenes with the properties and if this might lead to some issues down the line? Commented Jun 19 at 9:40
  • 1
    SFC's (single file components) are compiled into working javascript. defineProps is a compiler macro (therefore does not have to be imported) which tells the compiler to define the props. It will be compiled into something like the following (simplified): ``` { props: ['jsonUrl'], setup(props) { // Rest of your component code } } ``` As you can see, the rest of your code will be put into the setup method, which will immediately have access to the props variable.
    – Sjoertjuh
    Commented Jun 19 at 10:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.