web-dev-qa-db-ja.com

Svelte.js-新しい小道具で子コンポーネントを再レンダリングする方法?

私はSvelte.jsを使用してマルチステップフォームの作成に取り組んでいますが、各フォームページを一意のプロップでレンダリングする問題に遭遇しました。

ここに私が何を意味するかを示す簡単なデモがあります:

// 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要素で確認できます。ただし、label要素とinput要素は、最初のページとまったく同じです。ラッピングid要素のdivid要素のinputも変更されていません。

inputに入力してページを変更しても、テキストは変わりません。

私の目標は、FormPageが変更されたときにpageSelectedコンポーネントを再レンダリングし、inputlabelにこれらの新しい小道具に基づいて値を変更させることです。また、ページを変更すると、inputに既に入力されているテキストが更新されて空になるはずです(入力に初期値が指定されていないため)。

React.jsでマルチステップフォームを作成したら、key状態が変化するたびにFormPageが確実に再レンダリングされるように、一意のpageSelected属性を使用します。しかし、私はSvelte.jsで同様のことを行う方法がわかりません。

助言がありますか?

UPDATE:

StackOverflowで question を読んだ後、inputおよびlabel要素を変更して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内のテキストは変更されません。

入力の値も更新する方法はありますか?小道具が変更されるたびに完全に新しい要素を作成することが私のユースケースにとって理想的ですが、Svelteは同じ基本的なDOMノードで変更されたいくつかの属性のみを更新しているようです。

スベルトはこの状況で要素を再現するように言われることができますか?

更新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>

これにより、入力値の更新に関する当面の問題が解決されます。

onMountafterUpdate、およびonDestroy関数を追加して、コンポーネントの経時変化を確認しました。

最初にonDestroy関数が呼び出され、その後onMountが呼び出されます。これらは両方とも一度だけ発砲します。ただし、afterUpdateはプロップが変更されるたびに起動します。これは、コンポーネントが再作成されていなかったという私の疑いを裏付けています。

6
always_testing

これを行う簡単な方法があります。 pageDataFormPage更新は、const {name, label} = pageData;を使用しているときに問題になります。基本的に、namelabelおよびpageDataパラメーターの値を、それぞれnameおよびlabelの2つの定数に割り当てます。これらの2つの変数は、親コンポーネントにバインドされなくなりました。これを修正するには、以下のようにpageDataFormPageを直接使用します。

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>

注:undefinedが渡されない場合にコンパイラーがpageDataエラーを発生させないようにする場合は、pageData{}のように空のオブジェクトexport let pageData = {};として初期化できます。

inputの問題については、上記のvalueに示すように、formPagesbindに追加し、次にvalueFormPageからpageData.valueに追加するのが最も簡単です。

新しいformPagesデータ

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

[〜#〜] repl [〜#〜] の実際の例を示します。

1
nash11