上下文
大多数状态是组件级状态,其生命周期与组件相同。但是,也存在部分或应用程序范围的状态,也需要以某种方式进行处理。
最简单的方法是创建全局状态并导入它。
export const const myGlobalState: {
user: {};
}
myGlobalState = function $state<{
user: {};
}>(initial: {
user: {};
}): {
user: {};
} (+1 overload)
namespace $state
$state({
user: {}
user: {
/* ... */
}
/* ... */
});
<script>
import { myGlobalState } from './state.svelte';
// ...
</script>
但这有一些缺点
- 只有在您的全局状态仅在客户端使用时才能安全地工作 - 例如,当您构建仅在客户端渲染组件的单页应用程序时。如果您的状态最终在服务器上进行管理和更新,则可能最终在会话和/或用户之间共享,从而导致错误
- 它可能会给人们一种错误的印象,即某些状态是全局的,而实际上它应该只在应用程序的特定部分使用
为了解决这些缺点,Svelte 提供了一些context
原语来缓解这些问题。
设置和获取上下文
要将任意对象与当前组件关联,请使用setContext
。
<script>
import { setContext } from 'svelte';
setContext('key', value);
</script>
然后,子组件(包括插槽内容)可以使用getContext
访问该上下文。
<script>
import { getContext } from 'svelte';
const value = getContext('key');
</script>
setContext
和 getContext
解决了上述问题
- 状态不是全局的,它作用域到组件。这样,在服务器上渲染组件并不会泄露状态是安全的
- 很清楚状态不是全局的,而是作用域到特定的组件树,因此无法在应用程序的其他部分使用
setContext
/getContext
必须在组件初始化期间调用。
上下文本身不是反应式的。如果需要在上下文中使用反应式值,则可以将$state
对象传递到上下文中,其属性将是反应式的。
<script>
import { setContext } from 'svelte';
let value = $state({ count: 0 });
setContext('counter', value);
</script>
<button onclick={() => value.count++}>increment</button>
<script>
import { getContext } from 'svelte';
const value = getContext('counter');
</script>
<p>Count is {value.count}</p>
要检查父组件的上下文中是否已设置给定的key
,请使用hasContext
。
<script>
import { hasContext } from 'svelte';
if (hasContext('key')) {
// do something
}
</script>
您还可以检索属于最近父组件的整个上下文映射,方法是使用getAllContexts
。例如,如果您以编程方式创建组件并希望将现有上下文传递给它,这将非常有用。
<script>
import { getAllContexts } from 'svelte';
const contexts = getAllContexts();
</script>
封装上下文交互
上述方法对如何使用它们没有明确的意见。当您的应用程序规模扩大时,值得将设置和获取上下文封装到函数中并对其进行正确类型化。
import { function getContext<T>(key: any): T
Retrieves the context that belongs to the closest parent component with the specified key
.
Must be called during component initialisation.
getContext, function setContext<T>(key: any, context: T): T
Associates an arbitrary context
object with the current component and the specified key
and returns that object. The context is then available to children of the component
(including slotted content) with getContext
.
Like lifecycle functions, this must be called during component initialisation.
setContext } from 'svelte';
let let userKey: symbol
userKey = var Symbol: SymbolConstructor
(description?: string | number) => symbol
Returns a new unique Symbol value.
Symbol('user');
export function function setUserContext(user: User): void
setUserContext(user: User
user: type User = /*unresolved*/ any
User) {
setContext<User>(key: any, context: User): User
Associates an arbitrary context
object with the current component and the specified key
and returns that object. The context is then available to children of the component
(including slotted content) with getContext
.
Like lifecycle functions, this must be called during component initialisation.
setContext(let userKey: symbol
userKey, user: User
user);
}
export function function getUserContext(): User
getUserContext(): type User = /*unresolved*/ any
User {
return getContext<User>(key: any): User
Retrieves the context that belongs to the closest parent component with the specified key
.
Must be called during component initialisation.
getContext(let userKey: symbol
userKey) as type User = /*unresolved*/ any
User;
}