问题描述
我不明白如何在组件中使用可写存储并且仍然让 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();
用法
<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 })]}
此代码将与您的代码执行相同的操作,不同之处在于它直接从商店读取值,并且因为它直接引用商店,所以会相应地更新。