从可组合项访问 ref 值(第 2 部分)

Accessing ref values from composable (part 2)

这是我上一个问题的后续问题:

这是我的应用程序代码:

<template>
  {{ reversed_names }}
</template>

<script>
import { ref, watchEffect } from "@vue/runtime-core";
import getData from "./composables/getData";
import reverseNames from "./composables/reverseNames";

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

    const reversed_names = ref({});

    watchEffect(() => {
      const reversed_names = reverseNames(names_data.value);
      console.log("revnames inside watchEffect", reversed_names.value);
    });
    console.log("revnames outside watchEffect", reversed_names);

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

这里是 reverseNames 函数:

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

const reverseNames = (names_data) => {
  const reverse_names = ref({})
  var filenames = Object.keys(names_data)
  for (let f in filenames) {
    var filename = filenames[f]
    reverse_names.value[filename] = {}
    var members = names_data[filename]["members"]
    for (let n in members) {
      let name = members[n];
      var reverseName = name.split("").reverse().join("");
      reverse_names.value[filename][name] = reverseName
    }
  }
  return reverse_names
};

export default reverseNames

watchEffect 在那里,所以我可以在从文件加载数据后使用 names_data (请参阅上面的链接问题)。 代码在调用 reverseNames 之前工作正常。 names_data.value 包含以下内容:

{ "test1.json": 
    { "members": 
        { "0": "Alice", 
          "1": "Bob", 
          "2": "Charlie" 
        } 
    }, 
  "test2.json": 
    { "members": 
        { "0": "David", 
          "1": "Elizabeth", 
          "2": "Fred" 
        } 
    } 
}

这是令人困惑的部分:

watchEffect 函数内,控制台显示函数中正确的 return 字典。 但是,在 watchEffect 函数之外,控制台只显示在 watchEffect() 调用之前定义的空 ref({})

它是由setup()return编辑并显示在模板中的空字典。

如何从 watchEffect 中获取 setup() 到 return 的 reversed_names

const reversed_names outside 和 inside watchEffect 函数作用域不同,不相关的变量。 reversed_names 内部函数作用域遮蔽了父作用域中的另一个作用域。

ref 是一种模式,它在 JavaScript 中利用了对象通过引用传递,而不是通过值传递。这意味着它是一个 ref 而不是需要在每个需要保留反应性的地方传递的值,并注意它在 Vue 应用程序的上下文中使用。永远不要重新分配包含 ref 的变量,而是 value 属性 需要重新分配。

reverseNames 不是通用的辅助函数,而是特定于 Vue 的,因此可以接受引用。 reverse_names 没有很好的用途,因为它没有传递到任何地方,因此无法从使用 ref 模式中获益。可能是:

const reverseNames = (namesDataRef) => {
  const reverse_names = {} // not a ref
  var filenames = Object.keys(namesDataRef.value)
    reverse_names[filename] = {}
      ...
      reverse_names[filename][name] = reverseName
    }
  }

  namesDataRef.value = reverse_names;
  // doesn't need to return anything because it uses refs
}

const reversed_names = ref({});

watchEffect(() => {
  reverseNames(reversed_names);
  console.log("revnames inside watchEffect", reversed_names.value);
});

这是一个反模式。如果 reverseNames 使用异步副作用或任何可能触发在 reverseNames 调用期间无法跟踪的更改,这将是有意义的,类似于 。但它是同步的,只影响一个 ref,所以没有理由使用反应性。相反,可以将反应性提升给调用者:

const reverseNames = (namesData) => {
  const reverse_names = {} // not a ref
  ...
  return reverse_names
}

const reversed_names = ref({});

watchEffect(() => {
  reversed_names.value = reverseNames(names_data.value);
  console.log("revnames inside watchEffect", reversed_names.value);
});

如果没有副作用 (console.log),就不需要 watchEffect,它可以是计算的 ref:

const reversed_names = computed(() => reverseNames(names_data.value));