根据用户输入组合苗条的商店



我有以下苗条的商店:

export type SessionStore = {
session?: Session,
sessionType?: SessionType,
inputs: []
}

inputs字段的生成将根据会话的类型而改变:

  • 如果会话类型为'local',它将从用户的键盘生成
  • 如果会话类型为'online',它将通过网络提供

我有一个自定义存储,它根据用户的操作生成会话状态:

function makeSessionStore() {
const {subscribe, set, update} = writable(initialValue());
return {
subscribe,
createLocalSession: () => update(() => ({
session: {state: SessionState.RUNNING},
sessionType: SessionType.LOCAL,
inputs: [] // <--- how to generate this based on the session type?
})),
createNetworkSession: () => createSession().then(session => update(() => ({
session,
sessionType: SessionType.NETWORK,
inputs: []
})))
reset: () => set(initialValue())
}
}

我的问题:如何将响应式存储属性附加到输入属性?

例如,我是如何从用户的键盘获取输入的:

const keysPressed: Readable<string[]> = readable([], function(set) {
let keys = [];
const onKeydown = ({key}) => {
if (keys.includes(key)) {
return;
}
keys = [...keys, key];
set(keys);
}
const onKeyup = ({key}) => {
if (!keys.includes(key)) {
return;
}
keys = keys.filter(k => k !== key);
set(keys);
}
document.addEventListener('keydown', onKeydown);
document.addEventListener('keyup', onKeyup);
return () => {
document.removeEventListener('keydown', onKeydown);
document.removeEventListener('keyup', onKeyup);
}
})

我希望使用输入的组件不知道幕后的策略切换,他们应该能够像这样使用输入:

import {sessionStore} from './session';
console.log($sessionStore.inputs) // ['CONTROL', 'w']

为了解决这个问题,我最终使用了插槽组件而不是存储。

基本思想:将依赖于输入的组件包装在定义输入类型的包装器中。

{#if !session}
<h1>no session</h1>
{:else if session.type === SessionType.LOCAL}
<LocalSessionWrapper let:inputs={inputs}>
<slot inputs={inputs}></slot>
</LocalSessionWrapper>
{:else}
{#if session.state === SessionState.PENDING}
<h3>waiting for other player...</h3>
{:else if session.state === SessionState.CLOSED}
<h3>game over!</h3>
{:else if session.state === SessionState.RUNNING}
<NetworkSessionWrapper let:inputs={inputs}>
<slot inputs={inputs}></slot>
</NetworkSessionWrapper>
{:else }
<h3>unknown game state</h3>
{/if}
{/if}

包装器组件使用store来定义输入源:

LocalSessionWrapper:

<script lang="ts">
import {localSessionInputs, Session} from "./game/session";
export let session: Session;
</script>
<slot inputs={$localSessionInputs}></slot>

最新更新