如何触发/强制更新 Svelte 组件

Leo*_*one 11 svelte

我试图让我的头脑围绕苗条的 3 反应性事情......

  1. 我想在单击按钮时强制刷新 UI。我正在使用一个自定义组件AsyncFetcher,它接受 HTTP 发布数据,并data为其插槽返回对象(http 发布结果)。

  2. 我想要一个禁用功能。因此,当单击“禁用”按钮时,会调用 http api,然后刷新数据视图。

<script>
    export let id

    function onDisable() {
        fetch('disable-api-url', {id: id})
        // Then ??
        // What to do after the fetch call, to refresh the view
    }
</script>

<AsyncFetcher postParam={id} let:data>
    {data.name}

    <button on:click={??}>Refresh</button>
    <button on:click={onDisable}>Disable Item</button>
</AsyncFetcher>
Run Code Online (Sandbox Code Playgroud)

我试图on:click={() => id=id}欺骗它刷新无济于事。Ifid本来是一个对象而不是字符串id={...id}会起作用,不幸的是,这里不是这种情况。

实现这一目标的正确方法是什么?

Cam*_*eln 9

虽然Rich Harris给出了一个完全有用的答案,但这里有一个强制 Svelte 更新组件以反映其数据的外部更改的解决方案(也在此处发布)。

main.js ; 在线示例中的香草,没有特殊变化:

import App from './App.svelte';

var app = new App({
    target: document.body
});

export default app;
Run Code Online (Sandbox Code Playgroud)

索引.html ; 注意window.neek = {...}

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Svelte app</title>
    <script>
        window.neek = { nick: true, camp: { bell: "Neek" }, counter: 0 };
    </script>
    <script defer src='/build/bundle.js'></script>
</head>
<body>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

App.svelte ; 注意$: notneek = window.neekwindow.neek.update = ...

<script>
    let name = 'world';
    $: notneek = window.neek;

    function handleClick() {
        notneek.counter += 1;
    }

    window.neek.update = function () {
        notneek = notneek;
    }
</script>

<h1>Hello { notneek.camp.bell }!</h1>

<button on:click={handleClick}>
    Clicked {notneek.counter} {notneek.counter === 1 ? 'time' : 'times'}
</button>
Run Code Online (Sandbox Code Playgroud)

由于该update函数在 的范围内App.svelte,因此可以在通过 调用时强制重新渲染window.neek.update()。此设置window.neek.counter用于按钮 (via notneek.counter)使用的内部数据,并允许neek.camp.bell = "ish"在组件外部更新深层属性 (例如) 并neek.update()在调用一次后进行反射。

在控制台中,键入window.neek.camp.bell = "Bill"并注意Hello Neek!尚未更新的内容。现在,window.neek.update()在控制台中输入,UI 将更新为Hello Bill!.

最重要的是,您可以在update函数中任意细化,以便只同步您想要同步的部分。


Ric*_*ris 8

使用组件来管理获取是非常非常规的。通常,您会在 内部onMount或事件处理程序中获取数据:

<script>
  import { onMount } from 'svelte';

  let initialData;
  let otherData;

  onMount(async () => {
    const res = await fetch('some-url');
    initialData = await res.json();
  });

  async function update() {
    const res = await fetch('some-other-url');
    otherData = await res.json();
  }
</script>

{#if initialData}
  <p>the data is {initialData.something}</p>
{/if}

<button on:click={update}>update</button>
Run Code Online (Sandbox Code Playgroud)


Ary*_*hur 7

要获取数据,请使用await块

<script>
    async function fetchData() {
        const res = await fetch('/api')
        const data = await res.json()

        if (res.ok) {
            return data
        } else {
            throw new Error(data)
        }
    }
</script>

<style>
    .error {
        color: red;
    }
</style>

{#await fetchData}
    <p>Fetching...</p>
{:then data}
    <div>{JSON.stringify(data)}</div>
{:catch error}
    <div class="error">{error.message}</div>
{/await}
Run Code Online (Sandbox Code Playgroud)

要刷新数据,您需要通过更新一段相关状态来触发重新渲染,因为这将重新运行等待块。您可以通过将获取函数存储在一个状态中并在单击刷新按钮时重新分配它来触发重新渲染:

<script>
    async function fetchData() {
        const res = await fetch('/api')
        const data = await res.json

        if (res.ok) {
            return data
        } else {
            throw new Error(data)
        }
    }

    let promise = fetchData()
</script>

<style>
    .error {
        color: red;
    }
</style>

<button on:click="{() => {promise = fetchdata()}}">Refresh</button>

{#await promise}
    <p>Fetching...</p>
{:then data}
    <div>{JSON.stringify(data)}</div>
{:catch error}
    <div class="error">{error.message}</div>
{/await}
Run Code Online (Sandbox Code Playgroud)