我正在使用Svelte.js创建多步骤表单,但是在使用唯一 Prop 呈现每个表单页面时遇到了问题。

这是一个简单的演示,向您展示我的意思:

// App.svelte

<script>
    import FormPage from "./FormPage.svelte";
    let formNode;

    let pageSelected = 0;

    let formPages = [
        {
            name: "email",
            label: "Email"
        },
        {
            name: "password",
            label: "Password"
        }
    ];

    const handleIncPage = () => {
        if(pageSelected + 1 < formPages.length)
        pageSelected = pageSelected + 1;
    }

    const handleDecPage = () => {
        if(pageSelected -1 > -1)
        pageSelected = pageSelected - 1;
    }
</script>

<form bind:this={formNode}>
    <FormPage pageData={formPages[pageSelected]} />
</form>

<button on:click={handleDecPage}>Back</button>
<button on:click={handleIncPage}>Next</button>

<p>
    Page Selected: {pageSelected}
</p>

这是FormPage组件:
// FormPage.svelte

<script>
    export let pageData;

    const {name, label} = pageData;
</script>

<div id={`form-page-${name}`}>
    <label>Label: {label}</label>
    <input type="text" name={name} id={`input-${name}`} />
</div>

<pre>{JSON.stringify(pageData, null, 2)}</pre>

当我运行应用程序和inc/dec pageSelected时,pageData属性成功更改-如pre元素所示。但是,labelinput元素与第一页上的元素完全相同。包装的id元素的divid元素的input也保持不变。

当我键入input并更改页面时,文本保持不变。

我的目标是:在FormPage更改时重新呈现pageSelected组件,并根据这些新 Prop 使inputlabel更改其值。也应该是这样的情况,当我更改页面时,已经键入input的文本应该更新并且为空(因为没有为输入提供初始值)。

在React.js中完成多步骤表单后,我将使用唯一的key属性来确保每次FormPage状态更改时都重新发布我的pageSelected。但是我不确定如何在Svelte.js中执行类似的操作。

有什么建议么?

更新:

在StackOverflow上阅读了question之后,我发现了如何更改inputlabel元素以及id属性。这是我更新的FormPage组件:
// FormPage.svelte

<script>
    export let pageData;

    $: name = pageData.name;
    $: label = pageData.label;

</script>

<div id={`form-page-${name}`}>
    <label>Label: {label}</label>
    <input type="text" name={name} id={`input-${name}`}  />
</div>

<pre>{JSON.stringify(pageData, null, 2)}</pre>

但是,input内的文本仍保持不变。

有没有办法也更新输入的值?每次 Prop 更改时,创建一个全新的元素对我的用例来说都是理想的选择,但是看来Svelte只会更新在同一基础DOM节点上更改的少数属性。

在这种情况下可以告诉Svelte重新创建元素吗?

更新2

因此,我想出了一种方法来更改输入的值。这是我更新的FormPage组件:
// FormPage.svelte

<script>
    export let pageData;

        import {onMount, afterUpdate, onDestroy} from "svelte";

        let inputNode;

        $: name = pageData.name;
        $: label = pageData.label;
        $: value = pageData.initialValue || "";

        onMount(() => {
            console.log("Mounted");
        });

        afterUpdate(() => {
            console.log("Updated");
            inputNode.value = value
        });

        onDestroy(() => {
            console.log("Destroyed");
        });

</script>

<div id={`form-page-${name}`}>
    <label>Label: {label}</label>
    <input type="text" name={name} id={`input-${name}`} bind:this={inputNode}  />
</div>

<pre>{JSON.stringify(pageData, null, 2)}</pre>

这解决了更新输入值的直接问题。

我添加了onMountafterUpdateonDestroy函数,以查看组件随时间的变化。

首先,调用onDestroy函数,然后调用onMount。这些都只发射一次。但是,每次 Prop 更改时,afterUpdate都会触发。这证实了我对未重新创建组件的怀疑。

最佳答案

有一种更简单的方法可以做到这一点。 pageData在您的FormPage中更新,问题是当您使用const {name, label} = pageData;时,您基本上是将namelabelpageData参数的值分别分配给两个常量namelabel。这两个变量不再绑定(bind)到父组件。为了解决此问题,请直接在pageData中使用FormPage,如下所示。

FormPage.svelte

<script>
    export let pageData;
</script>

<div id={`form-page-${pageData.name}`}>
    <label>Label: {pageData.label}</label>
    <input type="text" name={pageData.name} bind:value={pageData.value} id={`input-${pageData.name}`} />
</div>



对于input问题,最简单的方法是将value添加到formPages中,然后将bind将该value附加到pageData.value中,如上面的FormPage所示。

新的formPages数据

let formPages = [{
    name: "email",
    label: "Email",
    value: ""
}, {
    name: "password",
    label: "Password",
    value: ""
}];

这是REPL上的工作示例。

关于javascript - Svelte.js-如何使用新 Prop 重新渲染子组件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58011307/

10-09 23:21