Notes while going throught: https://svelte.dev/tutorial/
Personal thoughts:
- pretty quick to get through
- excited that it's a compiled language
- types? compatible with typescript, since you also need to invoke it like the
ts
compiler? - (now that i think about it, it is unlikely to be compatible with ts because they both target javascript, which makes it impossible to chain the two compilers, which is a shame)
- [edit] it just might be possible to use TS with svelte: sveltejs/sapper#760
Declare reactive elements with the $:
declarator
(this is apparently a word):
<script>
let count = 0
$: doubled = count * 2 // svelte interprets this as code to be re-run whenever any of the referenced values change
function countHandler(){
count ++
}
</script>
<button on:click={countHandler}>
Count {count} {count === 1 ? 'time':'times'}
</button>
<p>Doubled: {double}</p>
The reactive declarator can also be used to designate reactive functions e.g. functions that are called when their referenced values change:
<script>
let name = 'Bob'
// Each time `name` changes, `console.log` is run again, printing a new line to the console
$: console.log(`${name} has entered the building.`)
function nameChange(src,target){
src = target
}
</script>
<button on:click={nameChange(name,"Bill")}>
Change Name
</button>
You can also group reactive declarations as an arbirtary block:
let count = 0
$: {
console.log(`the count is ${count}`);
console.log(`double the count is ${count * 2});
}
You can also put in an if
statement:
let count = 0
$: if count === 10 {
console.log(`you've reached a count of ${count}; please stop)
}
Svelte's reactivity is triggered by assignmnets. Doing things like calling
push
orsplice
on an array doesn't trigger an assignment, not allowing Svelte to react to it.A workaround is to add an arbitrary assignment whenever you call a
push
:function addNumber(arr){ arr.push(arr.length + 1) arr = arr }
Or skip using the
push
method altogether:function addNumber(arr){ arr = [...arr, arr.length + 1] }
- Each
.svelte
file is a single component. - You don't have to export the component e.g. like in Node or CommonJS
- Instead, you import the whole
.svelte
file withimport Nested from './Nested.svelte'
- You can then use the component like you would a React component e.g.
<Nested />
- You can export parameters or props in components to allow the parent component access to these parameters.
Example:
// Nested.svelte
<script>
export let answer,
correct = true; // you can set a default value.
// when the component is called without specifying a value for 'correct',
// it will fall back to this value.
</script>
<p>The answer is {answer}; did you get it correct? {correct}</p>
// ----
// App.svelte
<script>
import Nested from './Nested.svelte';
</script>
<Nested answer={42} correct={true} />
You can also pass an object as a prop!
// Info.svelte
<script>
export let name, version, speed, website;
</script>
<p>
The <code>{name}</code> package is {speed} fast.
Download version {version} from <a href="https://www.npmjs.com/package/{name}">npm</a>
and <a href={website}>learn more here</a>
</p>
// ---
// App.svelte
<script>
import Info from './Info.svelte';
const pkg = {
name: 'svelte',
version: 3,
speed: 'blazing',
website: 'https://svelte.dev'
};
</script>
<Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
You can also use the spread operator to automatically distribute object contents
into their corresponding prop holders. That is, you could call the <Info/>
component like this:
<Info {...pkg}/>
// The above code produces the same result as:
// <Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
// Because the fields of the pkg object are the same as the prop names the Info.svelte
// component is looking for.
To show that it works:
- Add an
updated: true
field to thepkg
object. - To the
<p>
component inInfo.svelte
, addUpdated?: {updated}
inside the<p>
tags. - In
App.svelte
, attempt to invoke the component by using the existing<Info name=... />
call. - Add another
Info
component, but using the spread operator:<Info {...pkg}/>
You'll see that the first <Info name=... />
component now displays undefined
where we would expect
to see the value of updated
, but <Info {...pkg}/>
contains the correct value for updated
.
This is way better than how we access objects and variables in Vue.
INFO: You can allow access to all props in the component by allowing access to
$$props
directly In your component. E.g.<ul> <li>This exposes all props in the component as an object: {$$props}</li> <li>You can access any prop inside <code>$$props</code> like this: {$$props.propName}</li> </ul>
- Conditionally render markup in components by wrapping it in an
{#if}{/if}
block.
NOTE: Unlike in React, you don't need to make sure that your component is encapsulated by a single tag.
For example:
<script>
let user = { loggedIn: false };
function toggle() {
user.loggedIn = !user.loggedIn;
}
</script>
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{/if}
{#if !user.loggedIn}
<button on:click={toggle}>
Log in
</button>
{/if}
You can also use an {:else}
:
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
<button on:click={toggle}>
Log in
</button>
{/if}