Svelte 访问子组件脚本标记中的存储变量

Svelte access a store variable in child component script tag

我有一个 Svelte & Sapper 应用程序,我在其中使用 Svelte 可写存储来设置一个具有初始空白字符串值的变量:

import { writable } from 'svelte/store';
export let dbLeaveYear = writable('');

在我的 Index.svelte 文件中,我正在导入它,然后计算出这个变量的值并进行设置(我在 ```[=37= 的 onMount 函数中执行此操作] 如果这是相关的):

<script>
  import {dbLeaveYear} from "../stores/store.js"

  function getCurrentLeaveYear() {
    const today = new Date();
    const currYear = today.getFullYear();
    const twoDigitYear = currYear.toString().slice(-2);
    const cutoffDate = `${twoDigitYear}-04-01`
    const result = compareAsc(today, new Date(cutoffDate));
    if (result === -1) {
      $dbLeaveYear = `${parseInt(twoDigitYear, 10) - 1}${twoDigitYear}`;
    } else {
      $dbLeaveYear = `${twoDigitYear}${parseInt(twoDigitYear, 10) + 1}`;
    }
  }

  onMount(() => {
    getCurrentLeaveYear();
  });
</script>

我在 Index.svelte

中呈现了一个子组件
<Calendar />

在 Calendar 子组件中,我正在导入变量并尝试访问它以对其执行转换,但我收到错误消息,它仍然是空白的 - 它似乎没有从 Index.svelte:

<script>
  import {dbLeaveYear} from "../stores/store.js"
  const calStart = $dbLeaveYear.slice(0, 2)
</script>

但是,如果我在具有 <p>{$dbLeaveYear}</p> 的同一日历子组件中使用 HTML 元素中的值,它会填充 Index.svelte.[=23 中的计算值=]

如何访问子组件的 <script> 标签内的 store 变量?这可能吗?我试过在 onMount 中赋值,我试过在一个函数中赋值 - 似乎没有任何效果,它总是说 $dbLeaveYear 是一个空字符串。

我需要这个值是动态的,因为休假年份值可以改变。

在深入研究您的问题之前,请允许我说您不应该直接改变存储变量,而应该使用提供的设置或更新方法。这避免了难以调试的错误:

  if (result === -1) {
      dbLeaveYear.set(() => `${parseInt(twoDigitYear, 10) - 1}${twoDigitYear}`);
    } else {
      dbLeaveYear.set(`${twoDigitYear}${parseInt(twoDigitYear, 10) + 1}`);
    }

除此之外,问题似乎是您的 auto-subscribe 商店不适合您的用例。您需要为此使用订阅 属性:

<script>
  import { dbLeaveYear } from "../stores/store.js"
  import { onDestroy, onMount } from "svelte"

  let yearValue;
  // Needed to avoid memory leaks
  let unsubscribe

  onMount(() => {
    unsubscribe = dbLeaveYear.subscribe(value => yearValue = value.slice(0, 2));
  })

  onDestroy(unsubscribe);
</script>

可能导致您遇到问题的另一件事是竞争条件。所以当子渲染时,父组件的更新还没有完成。然后你需要在渲染子组件中添加完整性检查。

这里的答案是 Sapper 预加载和从商店导出功能的能力的结合。

store.js 中导出您想要的变量的可写存储,以及一个计算值和设置可写存储的函数:

export let dbLeaveYear = writable('');

export function getCurrentLeaveYear() {
  const today = new Date();
  const currYear = today.getFullYear();
  const twoDigitYear = currYear.toString().slice(-2);
  const cutoffDate = `${twoDigitYear}-04-01`
  const result = compareAsc(today, new Date(cutoffDate));
  if (result === -1) {
    dbLeaveYear.set(`${parseInt(twoDigitYear, 10) - 1}${twoDigitYear}`);
  } else {
    dbLeaveYear.set(`${twoDigitYear}${parseInt(twoDigitYear, 10) + 1}`);
  }
}

在顶级 .svelte 文件中,在 "module" 脚本标记内使用 Sapper 的 preload() 函数来调用将计算值并设置可写存储的函数:

<script context="module">
  import {getCurrentLeaveYear} from '../stores/store'
  export async function preload() {
        getCurrentLeaveYear();
  }
</script>

然后在组件 .svelte 文件中,您可以导入存储变量,因为它已被预加载,所以它将在 <script> 标签中可用:

<script>
  import {dbLeaveYear} from '../stores/store'

  $: startDate = `20${$dbLeaveYear.slice(0, 2)}`
  $: endDate = `20${$dbLeaveYear.slice(-2)}`
</script>