Context(上下文)
大多数状态是组件级别的状态,其生命周期与组件相同。然而,也存在应用程序范围或页面范围的状态,这也需要进行相应的处理。
处理这种情况最简单的方法是创建全局状态并直接导入它。
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.js';
// ...
</script>
<script lang="ts">
import { myGlobalState } from './state.svelte.js';
// ...
</script>
这样做有几个缺点:
- 只有当您的全局状态仅在客户端使用时,它才能安全地工作 - 例如,当您正在构建一个不在服务端渲染任何组件的单页应用时。如果您的状态最终在服务端被管理和更新,它可能会在 sessions 和(或)用户之间共享,从而导致 bug
- 这可能给人一种误导性的印象,即某个状态是全局的,而实际上它只应该在你的应用程序的某个特定部分使用
为了解决这些缺点,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++}>增加</button>
<script lang="ts">
import { setContext } from 'svelte';
let value = $state({ count: 0 });
setContext('counter', value);
</script>
<button onclick={() => value.count++}>增加</button>
<script>
import { getContext } from 'svelte';
const value = getContext('counter');
</script>
<p>计数为 {value.count}</p>
<script lang="ts">
import { getContext } from 'svelte';
const value = getContext('counter');
</script>
<p>计数为 {value.count}</p>
要检查给定的 key
是否已在父组件的上下文中设置,可以使用 hasContext
。
<script>
import { hasContext } from 'svelte';
if (hasContext('key')) {
// 执行某些操作
}
</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;
}