私は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
要素のdiv
とid
要素のinput
も変更されていません。
input
に入力してページを変更しても、テキストは変わりません。
私の目標は、FormPage
が変更されたときにpageSelected
コンポーネントを再レンダリングし、input
とlabel
にこれらの新しい小道具に基づいて値を変更させることです。また、ページを変更すると、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>
これにより、入力値の更新に関する当面の問題が解決されます。
onMount
、afterUpdate
、およびonDestroy
関数を追加して、コンポーネントの経時変化を確認しました。
最初にonDestroy
関数が呼び出され、その後onMount
が呼び出されます。これらは両方とも一度だけ発砲します。ただし、afterUpdate
はプロップが変更されるたびに起動します。これは、コンポーネントが再作成されていなかったという私の疑いを裏付けています。
これを行う簡単な方法があります。 pageData
のFormPage
更新は、const {name, label} = pageData;
を使用しているときに問題になります。基本的に、name
のlabel
およびpageData
パラメーターの値を、それぞれname
およびlabel
の2つの定数に割り当てます。これらの2つの変数は、親コンポーネントにバインドされなくなりました。これを修正するには、以下のように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>
注:
undefined
が渡されない場合にコンパイラーがpageData
エラーを発生させないようにする場合は、pageData
を{}
のように空のオブジェクトexport let pageData = {};
として初期化できます。
input
の問題については、上記のvalue
に示すように、formPages
をbind
に追加し、次にvalue
をFormPage
からpageData.value
に追加するのが最も簡単です。
新しいformPages
データ
let formPages = [{
name: "email",
label: "Email",
value: ""
}, {
name: "password",
label: "Password",
value: ""
}];
[〜#〜] repl [〜#〜] の実際の例を示します。