【问题标题】:Accessing ref values from composable (part 2)从可组合访问 ref 值(第 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

【问题讨论】:

    标签: vue.js vuejs3 vue-reactivity


    【解决方案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));
    

    【讨论】:

    • 优秀。再次感谢您提供另一个有用的答案。
    猜你喜欢
    • 2022-01-08
    • 2015-01-15
    • 2011-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多