上下文
大多数状态是组件级状态,只要其组件存在,它就会存在。但是,还有部分范围或应用范围的状态,也需要以某种方式处理。
¥Most state is component-level state that lives as long as its component lives. There’s also section-wide or app-wide state however, which also needs to be handled somehow.
最简单的方法是创建全局状态并导入它。
¥The easiest way to do that is to create global state and just import that.
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>
但这有几个缺点:
¥This has a few drawbacks though:
只有当你的全局状态仅在客户端使用时,它才能安全地工作 - 例如,当你构建单页应用时,该应用不会在服务器上渲染任何组件。如果你的状态最终在服务器上进行管理和更新,则最终可能会在会话和/或用户之间共享,从而导致错误
¥it only safely works when your global state is only used client-side - for example, when you’re building a single page application that does not render any of your components on the server. If your state ends up being managed and updated on the server, it could end up being shared between sessions and/or users, causing bugs
可能会给人一种错误的印象,即某些状态是全局的,而实际上它只应该在应用的某个部分使用
¥it may give the false impression that certain state is global when in reality it should only used in a certain part of your app
为了解决这些缺点,Svelte 提供了一些 context
原语来缓解这些问题。
¥To solve these drawbacks, Svelte provides a few context
primitives which alleviate these problems.
设置和获取上下文(Setting and getting context)
¥Setting and getting context
要将任意对象与当前组件关联,请使用 setContext
。
¥To associate an arbitrary object with the current component, use setContext
.
<script>
import { setContext } from 'svelte';
setContext('key', value);
</script>
然后,上下文可供具有 getContext
的组件的子项(包括插槽内容)使用。
¥The context is then available to children of the component (including slotted content) with getContext
.
<script>
import { getContext } from 'svelte';
const value = getContext('key');
</script>
setContext
和 getContext
解决了上述问题:
¥setContext
and getContext
solve the above problems:
状态不是全局的,它的作用域是组件。这样,在服务器上渲染组件并且不会泄漏状态是安全的
¥the state is not global, it’s scoped to the component. That way it’s safe to render your components on the server and not leak state
很明显,状态不是全局的,而是局限于特定的组件树,因此不能在应用的其他部分使用
¥it’s clear that the state is not global but rather scoped to a specific component tree and therefore can’t be used in other parts of your app
必须在组件初始化期间调用
setContext
/getContext
。¥[!NOTE]
setContext
/getContext
must be called during component initialisation.
上下文本质上并不是反应性的。如果你需要上下文中的反应值,则可以将 $state
对象传递到上下文中,其属性将是反应性的。
¥Context is not inherently reactive. If you need reactive values in context then you can pass a $state
object into context, whose properties will be reactive.
<script>
import { setContext } from 'svelte';
let value = $state({ count: 0 });
setContext('counter', value);
</script>
<button onclick={() => value.count++}>increment</button>
<script lang="ts">
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>
<script lang="ts">
import { getContext } from 'svelte';
const value = getContext('counter');
</script>
<p>Count is {value.count}</p>
要检查给定的 key
是否已在父组件的上下文中设置,请使用 hasContext
。
¥To check whether a given key
has been set in the context of a parent component, use hasContext
.
<script>
import { hasContext } from 'svelte';
if (hasContext('key')) {
// do something
}
</script>
你还可以使用 getAllContexts
检索属于最近父组件的整个上下文映射。例如,如果你以编程方式创建组件并希望将现有上下文传递给它,这将非常有用。
¥You can also retrieve the whole context map that belongs to the closest parent component using getAllContexts
. This is useful, for example, if you programmatically create a component and want to pass the existing context to it.
<script>
import { getAllContexts } from 'svelte';
const contexts = getAllContexts();
</script>
封装上下文交互(Encapsulating context interactions)
¥Encapsulating context interactions
上面的方法对于如何使用它们非常不拘泥。当你的应用规模扩大时,将设置和获取上下文封装到函数中并正确键入它们是值得的。
¥The above methods are very unopinionated about how to use them. When your app grows in scale, it’s worthwhile to encapsulate setting and getting the context into functions and properly type them.
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;
}