如何正确使用非原始苗条商店?

问题描述

我不明白如何在组件中使用可写存储并且仍然让 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();

用法

它被用在一个 svelte 组件和一个 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>

想要的结果

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

更新

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

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

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

更新 2

现在 store 上的重置回调会阻止 DOM 上的反应性。 IE。按下重置后,DOM 或帮助程序中不会反映任何状态更改。

解决方法

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

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

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

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

此代码将与您的代码执行相同的操作,不同之处在于它直接从商店读取值,并且因为它直接引用商店,所以会相应地更新。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...