Skip to content

Instantly share code, notes, and snippets.

@zeddee
Last active August 27, 2019 13:01
Show Gist options
  • Save zeddee/ec939632fd3adeab4ff1d1487f8e6140 to your computer and use it in GitHub Desktop.
Save zeddee/ec939632fd3adeab4ff1d1487f8e6140 to your computer and use it in GitHub Desktop.

Svelte notes

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

Reactive Declarations

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 or splice 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]
}

Importing and Exporting components

  • 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 with import 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 the pkg object.
  • To the <p> component in Info.svelte, add Updated?: {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>

Flow control

  • 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}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment