2

Here is my Vue3 app code:

<template>
  {{ names_data }}
</template>

<script>
import getData from "./composables/getData"

export default {
  name: "App",
  setup() {
    var filenames = ["test1.json", "test2.json"];
    const { names_data, error, load_data } = getData(
      filenames
    );
    load_data();
    console.log("names", names_data)

    console.log("error", error)

    return { names_data };
  },
};
</script>

The imported composable function is the following:

import { ref } from "@vue/runtime-core";

const getData = (filenames) => {
  const names_data = ref([])
  const error = ref(null)

  const load_data = async () => {
    try {
      var promises = [];
      for (let i = 0; i < filenames.length; i++) {
        var filename = filenames[i]
        promises.push(
          fetch(`data/${filename}`).then(
            (res) => (res.ok && res.json()) || Promise.reject(res)
          )
        );
      }
      const data = await Promise.all(promises);
      names_data.value = data
    } catch (err) {
      error.value = err.message;
      console.log(error.value);
    }
  };
  return { names_data, error, load_data }
};

export default getData

and the data files contain the following:

test1.json

{
  "members": {
    "0": "Alice",
    "1": "Bob",
    "2": "Charlie"
  }
}

test2.json

{
  "members": {
    "0": "David",
    "1": "Elizabeth",
    "2": "Fred"
  }
}

This all works: I can see the names_data from the template showing on screen. However in the console the names_data appears as follows:

RefImpl {_shallow: false, dep: undefined, __v_isRef: true, _rawValue: Array(0), _value: Proxy} dep: Set(1) {ReactiveEffect} __v_isRef: true _rawValue: (2) [{…}, {…}] _shallow: false _value: Proxy {0: {…}, 1: {…}} value: (...) [[Prototype]]: Object

I want to be able to access the values in names_data for further processing, like putting them in a table, but when I do console.log(names_data.value) in the App I get a Proxy object to an empty array. I think the names_data object loses reactivity somehow, as it is not updated when load_data() is called. But it clearly is reactive in the template. So I'm confused about what is going on here.

How can I access the value of the ref to process it further?

2 Answers 2

2

It works as expected. Without using reactivity this would result in this popular race condition. The point of using reactivity is that values are reactive and can be composed in other places through composition API.

In this case it's unnecessary to wait for load_data to complete in setup body. It's supposed to be accessed at the time when a value is available:

const { names_data, error, load_data } = getData(...);
load_data();
watch(names_data, data => {
    console.log(data);
});
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I'm new to Vue and Javascript so the link is helpful.
I have a follow-up question here: stackoverflow.com/questions/70247984/…
0

Follow-up answer to Estus Flask's accepted answer:

If I make names_data a dictionary instead of a list, i.e. by doing

...
names_data = ref({})
...
...
    const data = await Promise.all(promises);
    for (let ind=0; ind<data.length; ind++) {
      let filename = filenames[ind]
      names_data.value[filename] = data[ind]
    }
...

then watch() no longer works. It has to be replaced in the setup() by watchEffect() as follows:

    watchEffect(() => {
      console.log("updated data", names_data.value)
    })

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.