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

Posted

技术标签:

【中文标题】从可组合访问 ref 值(第 2 部分)【英文标题】:Accessing ref values from composable (part 2) 【发布时间】:2022-01-11 19:25:26 【问题描述】:

这是我之前的问题的后续问题: Accessing ref values from composable

这是我的应用代码:

<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 函数中,控制台会显示该函数的正确返回字典。 但是,在watchEffect 函数之外,控制台只显示在watchEffect() 调用之前定义的空ref()

setup()返回并显示在模板中的空字典。

如何让setup()watchEffect 内部返回reversed_names

【问题讨论】:

【参考方案1】:

const reversed_names 外部和内部watchEffect 函数范围是不同的、不相关的变量。 reversed_names 在函数作用域内从父作用域遮蔽另一个。

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

reverseNames 不是通用帮助函数,而是特定于 Vue,因此可以接受 ref。 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 调用期间无法跟踪的更改,这将是有意义的,类似于another question。但它是同步的,除了单个 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));

【讨论】:

优秀。再次感谢您提供另一个有用的答案。

以上是关于从可组合访问 ref 值(第 2 部分)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linq 的 where 条件下从可为空的日期时间中删除时间部分

如何在空间可用时将多个JTable打印到单个页面

Vue.js中ref ($refs)用法举例总结及应注意的坑

访问 isnull 组合值

如何通过 ref 获取 textinput 的文本/值?

函数式编程思想:耦合和组合,第2部分