我有以下苗条的商店:
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>