0

我不明白如何在组件中使用可写存储并且仍然让 DOM 对状态的变化做出反应。

我想更改存储状态对象键并检索其最新值,然后将其用于组件中。

商店确实更新正确。唯一的问题是在存储状态更改时更新 DOM。

状态和存储类型

import { Writable, writable } from 'svelte/store';

export interface Words { [key: string]: boolean };

export interface SelectedWordsStore extends Writable<Words> {
  setWord: (key: string, state: boolean) => void;
  isWordSelected: (key: string) => boolean;
  reset: () => void;
}

店铺


function createSelectedWordsStore(): SelectedWordsStore {
  const state: Words = {};
  const store: Writable<Words> = writable(state);

  return {
    ...store,
    setWord: (key: string, isSelected: boolean) => store.update((words) => {
        words[key] = isSelected;
        return words;
    }),

    isWordSelected: (key: string) => {
      return state[key] ?? false;
    },

    reset: () => store.set({}),
  }
}

export const selectedWordsStore = createSelectedWordsStore();

用法

它被用在一个苗条的组件和一个 TS 帮助文件中

<script lang="ts">
    import Word from './components/Word.svelte';
    import { words, getWordKey } from './helpers/words';
    import type { IndexProps } from './helpers/words';
    import { isBingo } from './helpers/bingo';
    import { selectedWordsStore } from './selected-words.store';

    const onWordClick = ({ currentTarget }: TypedMouseEvent<HTMLDivElement>): void => {
        const parent = currentTarget.parentElement;
        const columnId = parent.dataset.columnId;
        const wordId = currentTarget.dataset.id;
        const key = getWordKey({ columnId, wordId })

        selectedWordsStore.setWord(
            key,
            !selectedWordsStore.isWordSelected(key),
        )

        isBingo(...); // <--- store used here as well
    }

    function isWordSelected(options: IndexProps): boolean {
        return selectedWordsStore.isWordSelected(getWordKey(options));
    }
</script>

<div class="container" data-testid="container">
    {#each words as wordGroup, columnId}
        <div data-column-id={columnId}>
            {#each wordGroup as word, wordId}

                <Word
                    on:click={onWordClick}
                    name={word}
                    isSelected={isWordSelected({ columnId, wordId })} <!-- USAGE -->
                    wordId={wordId}
                />

            {/each}
        </div>
    {/each}
</div>

期望的结果

我希望在调用onWordClickDOM 后重新检查isWordSelected并将最新的布尔值Word从商店传递给组件

更新

我找到了一个可行的解决方案

isSelected={$selectedWordsStore && isWordSelected({ columnId, wordId })}

但是,不确定这是最好的方法。有什么建议么?

更新 2

现在 store 上的 reset 回调会阻止 DOM 上的反应。也就是说,在按下重置后,DOM 或助手中不会反映任何状态更改。

4

1 回答 1

1

您的原始代码不起作用的原因是该行将isSelected={isWordSelected({ columnId, wordId })}在组件渲染时执行,并且仅在那个时刻执行。意味着渲染后的任何更改都不会显示。

您提出的解决方案通过让商店也成为等式的一部分来解决这个问题,当商店发生变化时,整个store && isSelected部分将重新执行。

在我看来,最好的方法是使用辅助方法放弃所有额外的复杂性,并直接从商店请求值:

  isSelected={$selectedWordsStore[getWordsKey({ columnId, wordId })]}

此代码将与您的代码执行相同的操作,只是它直接从存储中读取值,并且因为它直接引用存储,所以它会相应地更新。

于 2020-12-20T20:22:46.253 回答