The following example is from the svelte official docs.
<script>
async function getRandomNumber() {
const res = await fetch(`tutorial/random-number`);
const text = await res.text();
if (res.ok) {
return text;
} else {
throw new Error(text);
}
}
let promise = getRandomNumber(); -------------- How does this work?
function handleClick() {
promise = getRandomNumber();
}
</script>
<button on:click={handleClick}>
generate random number
</button>
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
My question is, when we are assigning 'promise' to a function 'call' as done above, it is supposed to call the function immediately. In the svelte repl, this does not happen, and random number is generated only on button click. HOWEVER, when I modify the code to fetch json from a simple express server, I don't even need to click the button- the server is called on app startup. (which is what you would expect). What magic is going on?
Although maybe not important, but here is the code I tried.
<script>
async function getNotes() {
const res = await fetch('http://localhost:3001/api/notes')
const json = await res.json()
if(res.ok) {
return json;
} else {
throw new Error(res)
}
}
let promise = getNotes();
function onClickGetNotes() {
promise = getNotes();
}
</script>
<div class="grid-item-container card">
<button on:click={onClickGetNotes}> Get Notes </button>
{#await promise}
.. Loading notes
{:then notes}
{#each notes as note (note.id)}
<div class="grid-item-container card">
<p class="grid-item"> ID is {note.id} </p>
<p class="grid-item"> Content is {note.content} </p>
<lable class="grid-item" for="important"> Important
<input class="grid-item" type="checkbox" id="important" checked={note.important}>
</lable>
</div>
{/each}
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
</div>
What is the best way to call the async function so that the json is only fetched on button click?
The following example is from the svelte official docs.
<script>
async function getRandomNumber() {
const res = await fetch(`tutorial/random-number`);
const text = await res.text();
if (res.ok) {
return text;
} else {
throw new Error(text);
}
}
let promise = getRandomNumber(); -------------- How does this work?
function handleClick() {
promise = getRandomNumber();
}
</script>
<button on:click={handleClick}>
generate random number
</button>
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
My question is, when we are assigning 'promise' to a function 'call' as done above, it is supposed to call the function immediately. In the svelte repl, this does not happen, and random number is generated only on button click. HOWEVER, when I modify the code to fetch json from a simple express server, I don't even need to click the button- the server is called on app startup. (which is what you would expect). What magic is going on?
Although maybe not important, but here is the code I tried.
<script>
async function getNotes() {
const res = await fetch('http://localhost:3001/api/notes')
const json = await res.json()
if(res.ok) {
return json;
} else {
throw new Error(res)
}
}
let promise = getNotes();
function onClickGetNotes() {
promise = getNotes();
}
</script>
<div class="grid-item-container card">
<button on:click={onClickGetNotes}> Get Notes </button>
{#await promise}
.. Loading notes
{:then notes}
{#each notes as note (note.id)}
<div class="grid-item-container card">
<p class="grid-item"> ID is {note.id} </p>
<p class="grid-item"> Content is {note.content} </p>
<lable class="grid-item" for="important"> Important
<input class="grid-item" type="checkbox" id="important" checked={note.important}>
</lable>
</div>
{/each}
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
</div>
What is the best way to call the async function so that the json is only fetched on button click?
Share Improve this question asked Nov 17, 2020 at 12:53 KHANKHAN 1152 silver badges10 bronze badges 4-
"What is the best way to call the async function so that the json is only fetched on button click?" Don't call
getNotes()
outside of the click event handler... – Heretic Monkey Commented Nov 17, 2020 at 12:56 - Thanks, but why can't I call getNotes() directly from on:click? Like on:click = {getNotes} – KHAN Commented Nov 17, 2020 at 13:03
- I don't know Svelte, so I can't answer that question. – Heretic Monkey Commented Nov 17, 2020 at 13:05
- Svelte is just supposed to be a piler, so any js logic should be applicable in svelte. That's why I am worried! – KHAN Commented Nov 17, 2020 at 13:07
2 Answers
Reset to default 3When I copy your code into a REPL as is, the number is generated immediately AND on button click. Which is what is expected and should happen indeed.
What is the best way to call the async function so that the json is only fetched on button click?
Well, don't call it before you need it. Not at ponent creation, if it's not what you want. You can simply have:
let promise
This would display "The number is undefined".
You can wrap this into an if
if you want to show the text only when there's something happening:
<button on:click={handleClick}>
generate random number
</button>
<button on:click={() => { promise = null }}>
reset
</button>
{#if promise != null}
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
{/if}
Or you can give a non-Promise initial value to your variable if you prefer:
let promise = 0
Or even a promise one if you want:
let promise = Promise.resolve(42)
Just adding this for my reference. This is what I ended up doing before Rix answered.
<script>
let notes = []
async function getNotes() {
const res = await fetch('http://localhost:3001/api/notes')
const json = await res.json()
notes = json
console.log('notes', notes)
}
async function onClickGetNotes() {
await getNotes()
}
</script>
<div class="grid-item-container card">
<h4 class="grid-item"> Find the best</h4>
<label class="grid-item" for="site-search">Suburb or Postcode</label>
<input class="grid-item" type="search" id="site-search" name="q">
<button on:click={onClickGetNotes}> Get Notes </button>
{#each notes as note (note.id)}
<div class="grid-item-container card">
<p class="grid-item"> ID is {note.id} </p>
<p class="grid-item"> Content is {note.content} </p>
<lable class="grid-item" for="important"> Important
<input class="grid-item" type="checkbox" id="important" checked={note.important}>
</lable>
</div>
{/each}
</div>