Svelte 中是否有 "nicer" 方法从导出的 prop 声明和更新多个变量?
Is there a "nicer" way in Svelte to declare and update multiple variables from an exported prop?
背景
我正在为我的公司开展一个项目。
我们决定在这个项目中使用 Svelte。我们正在监视来自此应用程序中微服务的信息。
我构建了一个组件,它从名为“值”的对象中获取信息,并使用销毁符号声明它的道具。该值将被更新。在每次更新时,“值”的道具都用于对它们进行计算,并直接在模板中渲染结果或道具。
这里是源码(省略不必要的部分):
<script>
let state = "default";
let dayDiff = 0;
let dateOutput;
let valuesAvailable;
export let value;
let {name, finished, started, running, lastRun, completion, messages} = value;
$: {
;({name, finished, started, running, lastRun, completion, messages} = value)
valuesAvailable = Object.keys(value).length > 0;
if(selectedItemStore === name) {
selectedItemStore.set(value)
}
if (valuesAvailable) {
if (completion) {
completion = Number(value.completion.slice(0, -1));
} else {
completion = 0;
}
const messageArray = Object.entries(messages);
if (running) {
state = 'running';
} else {
if (completion === 100) {
state = 'done'
}
if (messageArray.length > 0) {
state = "info";
}
}
if (finished) {
dateOutput = Utils.getRelOrAbsoluteDate(finished)
} else if (running && started) {
dateOutput = "running...";
} else {
state = "never-run";
dateOutput = "Did not run before"
}
if (completion < 100 && !running && started) {
state = 'error';
}
}
}
</script>
<div class={"item " + state + (selectedItemStore === value.name ? " selected" : "")} on:click={toggleSelection}>
<span class="name">{name}</span>
<iron-icon icon={iconMappings[state]}></iron-icon>
{#if state!=='never-run'}
<div class="bar">
<CompletionIndicator value={completion}/>
</div>
{/if}
<span class="date">
{dateOutput}
</span>
</div>
问题
这些行有问题:
<script>
export let value;
let {name, finished, started, running, lastRun, completion, messages} = value;
$: {
;({name, finished, started, running, lastRun, completion, messages} = value)
(...)
}
</script>
$: { ... } 中的代码在每次“值”改变时执行。我这样做是因为必须在每次渲染时重新进行“计算”。在“反应函数”之外,实际值被声明为在模板中使用。它们必须在反应函数范围之外声明,这样它们才能在实际的 Svelte 模板中使用。
结论
这是可行的,但首先不容易阅读。我还没有找到使它更具可读性和工作性的解决方案。
单行代码或另一种解决此问题的方法会很好。
你有什么想法吗?
编辑:
我们已经找到了一个很好的解决方案,在这个组件之外使用 {#key value} 语法标记为已接受的答案。
无论如何,就性能而言,仅使用带有反应式声明的 解决方案会更聪明。
如果道具太多,我更喜欢使用商店,但在你的情况下,为什么不检查父对象本身是否有任何变化:
<script>
export let value;
$: if (value) {
// do your magic
}
</script>
并且您可以在需要时直接使用value.porp
。
您可以使用 #key
块重新呈现您需要动态数据的组件。如果组件内部有转换,这可能是不可取的,因为它们需要一些变通方法 运行 正确地位于 #key
块内,但它可能对您的用例有所帮助。
这是一个更简化的示例,其中父项中的数据发生变化并且组件(具有解构的对象)重新呈现以匹配父项中的状态,而无需任何反应语句。这里有一个 REPL 可以试试。
App.svelte
<script>
import Component from './Component.svelte'
let value = {name: 'Creed Bratton', age: 30}
</script>
<input bind:value={value.name} />
<input type="number" bind:value={value.age} />
{#key value}
<Component {value} />
{/key}
Component.svelte
<script>
export let value;
let {name, age} = value
</script>
<div>
<p>
{name} - {age}
</p>
{#if age > 30}
<p>Wow, that is old</p>
{/if}
</div>
将它分成两个响应式语句,如下所示:
export let value;
$: ({name, finished, started, running, lastRun, completion, messages} = value);
$: {
(...)
}
背景
我正在为我的公司开展一个项目。
我们决定在这个项目中使用 Svelte。我们正在监视来自此应用程序中微服务的信息。
我构建了一个组件,它从名为“值”的对象中获取信息,并使用销毁符号声明它的道具。该值将被更新。在每次更新时,“值”的道具都用于对它们进行计算,并直接在模板中渲染结果或道具。
这里是源码(省略不必要的部分):
<script>
let state = "default";
let dayDiff = 0;
let dateOutput;
let valuesAvailable;
export let value;
let {name, finished, started, running, lastRun, completion, messages} = value;
$: {
;({name, finished, started, running, lastRun, completion, messages} = value)
valuesAvailable = Object.keys(value).length > 0;
if(selectedItemStore === name) {
selectedItemStore.set(value)
}
if (valuesAvailable) {
if (completion) {
completion = Number(value.completion.slice(0, -1));
} else {
completion = 0;
}
const messageArray = Object.entries(messages);
if (running) {
state = 'running';
} else {
if (completion === 100) {
state = 'done'
}
if (messageArray.length > 0) {
state = "info";
}
}
if (finished) {
dateOutput = Utils.getRelOrAbsoluteDate(finished)
} else if (running && started) {
dateOutput = "running...";
} else {
state = "never-run";
dateOutput = "Did not run before"
}
if (completion < 100 && !running && started) {
state = 'error';
}
}
}
</script>
<div class={"item " + state + (selectedItemStore === value.name ? " selected" : "")} on:click={toggleSelection}>
<span class="name">{name}</span>
<iron-icon icon={iconMappings[state]}></iron-icon>
{#if state!=='never-run'}
<div class="bar">
<CompletionIndicator value={completion}/>
</div>
{/if}
<span class="date">
{dateOutput}
</span>
</div>
问题
这些行有问题:
<script>
export let value;
let {name, finished, started, running, lastRun, completion, messages} = value;
$: {
;({name, finished, started, running, lastRun, completion, messages} = value)
(...)
}
</script>
$: { ... } 中的代码在每次“值”改变时执行。我这样做是因为必须在每次渲染时重新进行“计算”。在“反应函数”之外,实际值被声明为在模板中使用。它们必须在反应函数范围之外声明,这样它们才能在实际的 Svelte 模板中使用。
结论
这是可行的,但首先不容易阅读。我还没有找到使它更具可读性和工作性的解决方案。 单行代码或另一种解决此问题的方法会很好。 你有什么想法吗?
编辑:
我们已经找到了一个很好的解决方案,在这个组件之外使用 {#key value} 语法标记为已接受的答案。
无论如何,就性能而言,仅使用带有反应式声明的
如果道具太多,我更喜欢使用商店,但在你的情况下,为什么不检查父对象本身是否有任何变化:
<script>
export let value;
$: if (value) {
// do your magic
}
</script>
并且您可以在需要时直接使用value.porp
。
您可以使用 #key
块重新呈现您需要动态数据的组件。如果组件内部有转换,这可能是不可取的,因为它们需要一些变通方法 运行 正确地位于 #key
块内,但它可能对您的用例有所帮助。
这是一个更简化的示例,其中父项中的数据发生变化并且组件(具有解构的对象)重新呈现以匹配父项中的状态,而无需任何反应语句。这里有一个 REPL 可以试试。
App.svelte
<script>
import Component from './Component.svelte'
let value = {name: 'Creed Bratton', age: 30}
</script>
<input bind:value={value.name} />
<input type="number" bind:value={value.age} />
{#key value}
<Component {value} />
{/key}
Component.svelte
<script>
export let value;
let {name, age} = value
</script>
<div>
<p>
{name} - {age}
</p>
{#if age > 30}
<p>Wow, that is old</p>
{/if}
</div>
将它分成两个响应式语句,如下所示:
export let value;
$: ({name, finished, started, running, lastRun, completion, messages} = value);
$: {
(...)
}