如果在一个插槽中,Svelte 组件不会看到道具更新,但如果在另一个插槽中则会看到
Svelte component does not see prop update if in one slot, but does if in another slot
在下面的组件(称为“注释屏幕”)中,组件 DocPicker
让用户设置变量 selectedDoc
,这又应该更新两个组件:Form
和 SearchResultView
.
<script lang="ts">
import type { AppScreen, QuestionGouv } from '../../types.js';
import Screen from '../../Screen.svelte';
import DocPicker from './DocPicker/DocPicker.svelte';
import SearchResultView from '../../SearchResultView.svelte';
import Form from './Form.svelte';
export let screen: AppScreen;
let selectedDoc: QuestionGouv;
let isPickerOpen: boolean;
</script>
<Screen bind:screen>
<svelte:fragment slot="sidebar">
<DocPicker bind:picked={selectedDoc} bind:isOpen={isPickerOpen}/>
{#if selectedDoc}
<Form doc={selectedDoc}/>
{/if}
</svelte:fragment>
<svelte:fragment slot="content">
{#if selectedDoc}
<SearchResultView doc={selectedDoc} on:close={() => {selectedDoc = undefined}}/>
{/if}
</svelte:fragment>
</Screen>
问题是当selectedDoc
改变时Form
组件没有更新。第一次 selectedDoc
从 undefined
变为某个值时,组件 Form
会以正确的值出现,但如果稍后 selectedDoc
发生变化(因为用户使用 DocPicker
), 组件 Form
保持以前的值。
SearchResultView
每次都会更新,就像一个魅力,所以我虽然问题来自 Form
组件,但如果我在下一个复制行 <Form doc={selectedDoc}/>
到 SearchResultView
所在的位置(即在 <svelte:fragment slot="content">
中),这个 Form
的实例可以正常工作!同样,如果我将 SearchResultView
的另一个实例放入 <svelte:fragment slot="sidebar">
,则 SearchResultView
的这个实例不会更新。
所以好像和组件插入位置有关,即Screen
组件在哪个槽位。但是 Screen
组件非常简单,归结为:
<Sidebar>
<div class="screen-sidebar">
<slot name="sidebar"></slot>
</div>
</Sidebar>
<slot name="content"></slot>
Sidebar
组件也很简单:
<div class="sidebar">
<slot></slot>
</div>
好的,知道了。事实证明,问题的原因不在我提出问题的代码片段中。我在 DocPicker
组件中做了一些你可能根本不应该在 Svelte 中做的事情。 Svelte 编译器没有抱怨,但显然很困惑,这导致了我在问题中描述的奇怪行为。
以下是问题的详细信息以及我是如何找到它的。
我试着想出一个最小的工作示例,这样我就可以把它放在一个 Svelte REPL 中,当然问题没有重现。
因此,我尝试了从有问题的情况到失败的最小工作示例的许多中间步骤,以查看哪个精确步骤可以恢复错误。把它带回来的是 DocPicker
组件中的 bind:isOpen={isPickerOpen}
属性绑定。所以问题可能与此组件有关。
我查看了这个DocPicker
组件的代码,prop isOpen
的使用方式很奇怪。我什至留下了评论警告:
export let isOpen: boolean = true;
$: isOpen = !Boolean(picked);
// XXX is it good practice to "force" a variable that is also reactively assigned?
function openPicker() {
isOpen = true;
}
所以我想我现在对评论中的问题有了答案:不,这可能不是一个好主意。或者也许不是这样。如果这总是一个坏主意,Svelte 编译器在看到这个时会不会引发错误?
无论如何,我改变了 isOpen
的管理方式(不是通过反应性分配,而是通过命令式分配),现在它工作得很好。
在下面的组件(称为“注释屏幕”)中,组件 DocPicker
让用户设置变量 selectedDoc
,这又应该更新两个组件:Form
和 SearchResultView
.
<script lang="ts">
import type { AppScreen, QuestionGouv } from '../../types.js';
import Screen from '../../Screen.svelte';
import DocPicker from './DocPicker/DocPicker.svelte';
import SearchResultView from '../../SearchResultView.svelte';
import Form from './Form.svelte';
export let screen: AppScreen;
let selectedDoc: QuestionGouv;
let isPickerOpen: boolean;
</script>
<Screen bind:screen>
<svelte:fragment slot="sidebar">
<DocPicker bind:picked={selectedDoc} bind:isOpen={isPickerOpen}/>
{#if selectedDoc}
<Form doc={selectedDoc}/>
{/if}
</svelte:fragment>
<svelte:fragment slot="content">
{#if selectedDoc}
<SearchResultView doc={selectedDoc} on:close={() => {selectedDoc = undefined}}/>
{/if}
</svelte:fragment>
</Screen>
问题是当selectedDoc
改变时Form
组件没有更新。第一次 selectedDoc
从 undefined
变为某个值时,组件 Form
会以正确的值出现,但如果稍后 selectedDoc
发生变化(因为用户使用 DocPicker
), 组件 Form
保持以前的值。
SearchResultView
每次都会更新,就像一个魅力,所以我虽然问题来自 Form
组件,但如果我在下一个复制行 <Form doc={selectedDoc}/>
到 SearchResultView
所在的位置(即在 <svelte:fragment slot="content">
中),这个 Form
的实例可以正常工作!同样,如果我将 SearchResultView
的另一个实例放入 <svelte:fragment slot="sidebar">
,则 SearchResultView
的这个实例不会更新。
所以好像和组件插入位置有关,即Screen
组件在哪个槽位。但是 Screen
组件非常简单,归结为:
<Sidebar>
<div class="screen-sidebar">
<slot name="sidebar"></slot>
</div>
</Sidebar>
<slot name="content"></slot>
Sidebar
组件也很简单:
<div class="sidebar">
<slot></slot>
</div>
好的,知道了。事实证明,问题的原因不在我提出问题的代码片段中。我在 DocPicker
组件中做了一些你可能根本不应该在 Svelte 中做的事情。 Svelte 编译器没有抱怨,但显然很困惑,这导致了我在问题中描述的奇怪行为。
以下是问题的详细信息以及我是如何找到它的。
我试着想出一个最小的工作示例,这样我就可以把它放在一个 Svelte REPL 中,当然问题没有重现。
因此,我尝试了从有问题的情况到失败的最小工作示例的许多中间步骤,以查看哪个精确步骤可以恢复错误。把它带回来的是 DocPicker
组件中的 bind:isOpen={isPickerOpen}
属性绑定。所以问题可能与此组件有关。
我查看了这个DocPicker
组件的代码,prop isOpen
的使用方式很奇怪。我什至留下了评论警告:
export let isOpen: boolean = true;
$: isOpen = !Boolean(picked);
// XXX is it good practice to "force" a variable that is also reactively assigned?
function openPicker() {
isOpen = true;
}
所以我想我现在对评论中的问题有了答案:不,这可能不是一个好主意。或者也许不是这样。如果这总是一个坏主意,Svelte 编译器在看到这个时会不会引发错误?
无论如何,我改变了 isOpen
的管理方式(不是通过反应性分配,而是通过命令式分配),现在它工作得很好。