Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 88 additions & 89 deletions 04-store-login/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Let's start by learning how _stores_ work: in this example we will learn how to

# Step By Step Guide

- This example will take a starting point _00-scratch-typescript_
- This example will take a starting point _00-boiler-typescript_

- Let's install the packages.

Expand Down Expand Up @@ -63,7 +63,6 @@ _./src/pages/login-page.svelte_
width: 300px;
}
</style>

```

_./src/pages/home-page.svelte_
Expand Down Expand Up @@ -105,7 +104,7 @@ _./src/pages/home-page.svelte_

_./src/pages/index.ts_

```svelte
```ts
export { default as LoginPage } from "./login-page.svelte";
export { default as HomePage } from "./home-page.svelte";
```
Expand Down Expand Up @@ -134,7 +133,7 @@ _./src/common/navbar.svelte_

_./src/common/index.ts_

```svelte
```ts
export { default as NavBar } from "./navbar.svelte";
```

Expand All @@ -156,23 +155,23 @@ _./src/App.svelte_
</script>

<main>
<Router>
<NavBar />
<Route path="/">
<LoginPage />
</Route>
<Route path="home">
<HomePage />
</Route>
</Router>
<Router>
<NavBar />
<Route path="/">
<LoginPage />
</Route>
<Route path="home">
<HomePage />
</Route>
</Router>
</main>

<style>
main {
main {
display: grid;
grid-template-rows: auto 1fr;
flex-grow: 1;
}
}
</style>
```

Expand All @@ -181,18 +180,18 @@ _./src/App.svelte_
_./src/pages/login-page.svelte_

```diff
<script lang="ts">
+ import { useNavigate } from "svelte-navigator";
+ const navigate = useNavigate();
let username = "Mr. Nobody";
</script>

<div class="root">
<h1>Login Page</h1>
<input bind:value={username} />
- <button on:click={() => console.log("It should navigate to home page")}>Login</button>
+ <button on:click={() => navigate("home")}>Login</button>
</div>
<script lang="ts">
+ import { useNavigate } from "svelte-navigator";
+ const navigate = useNavigate();
let username = "Mr. Nobody";
</script>

<div class="root">
<h1>Login Page</h1>
<input bind:value={username} />
- <button on:click={() => console.log("It should navigate to home page")}>Login</button>
+ <button on:click={() => navigate("/home")}>Login</button>
</div>
```

- Let's give a try to what we have created:
Expand All @@ -206,17 +205,17 @@ npm run dev
- Login page.
- Home page.

- And there's a common component called _navBar_ that will be displayed on top of the app.
- And there's a common component called _NavBar_ that will be displayed on top of the app.

The behavior that we want to achieve:

- When the user logs in:
- The navBar should change to display the user's name.
- The home page should change to display the user's name.

Once that we are on the home page we want to be able to update the login name and this change should be reflected on the navBar and on the home page.
Once that we are on the home page we want to be able to update the login name and this change should be reflected on the nav bar and on the home page.

The userInformation should be globally accesible, so we don't need to pass it around using props.
The user information should be globally accessible, so we don't need to pass it around using props.

It seems like a good idea to use a _writable store_ to share the data.

Expand All @@ -226,9 +225,9 @@ Let's go for it:
case we will store an object, so we can check the difference between replacing
the value and updating it.

We can create an store
In order to create a store:

- We will import _writable_ store from _svelte-store_: this will allow
- We will import _writable_ store from _svelte-store_. This will allow
us to hold a global data and be able to update it.

- Then we will initialize the store with the initial value, it could be a simple string,
Expand Down Expand Up @@ -257,24 +256,24 @@ export * from "./user.store";
_./src/pages/login-page.svelte_

```diff
<script lang="ts">
import { useNavigate } from "svelte-navigator";
+ import { userInfoStore } from "../stores";
const navigate = useNavigate();
let username = "Mr. Nobody";

+ const handleLogin = (e) => {
+ userInfoStore.set({ username });
+ navigate("/home");
+ };
</script>

<div class="root">
<h1>Login Page</h1>
<input bind:value={username}/>
- <button on:click={() => navigate('home')}>Login</button>
+ <button on:click={handleLogin}>Login</button>
</div>
<script lang="ts">
import { useNavigate } from "svelte-navigator";
+ import { userInfoStore } from "../stores";
const navigate = useNavigate();
let username = "Mr. Nobody";

+ const handleLogin = (e) => {
+ userInfoStore.set({ username });
+ navigate("/home");
+ };
</script>

<div class="root">
<h1>Login Page</h1>
<input bind:value={username}/>
- <button on:click={() => navigate('home')}>Login</button>
+ <button on:click={handleLogin}>Login</button>
</div>
```

- If we use _set_ we are replacing the whole object without taking into consideration the previous value, we may want to keep a reference to the old object and use the spread operator to keep the previous values and just replace only the one affected by the change, we can do this by using the store _update_ method, it could be something like:
Expand All @@ -283,13 +282,13 @@ _./src/pages/login-page.svelte_

```diff
const handleLogin = (e) => {
- userInfoStore.set({ username });
+ userInfoStore.update(previous => ({ ...previous, username }));
- userInfoStore.set({ username });
+ userInfoStore.update(previous => ({ ...previous, username }));
navigate("/home");
};
```

- Cool, now let's hop onto the _navBar_ component and display the user's name:
- Cool! Now let's hop onto the _NavBar_ component and display the user's name:
- We will import the _userInfoStore_ that we have created.
- We will start by subscribing to store changes, and then update user Info.

Expand All @@ -310,43 +309,43 @@ _./src/common/navbar.svelte_
+ <h2>User Logged in: {userInfo.username}</h2>
```

This approach is okeish but we would have to take care of doing even some cleanup in the component (unsubscribe), Svelte offers us a short cut (just a reactive assignment):
This approach is ok-ish but we would have to take care of doing even some cleanup in the component (unsubscribe), Svelte offers us a short cut (just a reactive assignment):

- To access the value of the _userInfoStore_ we have to prefix the store with the
_$_ sign,
- We will ask to listen the userInfoStore for changes, in order to use this value we have to use the _$_ sign again (in this case to make reactive this piece of code, this would be similar
in React to useEffect [userInfoStore]).
in React to adding _userInfoStore_ to the dependencies of _useEffect_).

_./src/common/navbar.svelte_

```diff
<script lang="ts">
import { userInfoStore } from "./stores";
<script lang="ts">
import { userInfoStore } from "./stores";
- let userInfo = null;
-
- userInfoStore.subscribe(newUserInfo => {
- userInfo = newUserInfo;
- userInfo = newUserInfo;
- });
+ $: userInfo = $userInfoStore;
</script>
</script>

<h2>User Logged in: {userInfo.name}</h2>
```

> Note we don't need to define the _userInfoStore_ using _let_, _Svelte_ will detect this and
> Note we don't need to declare _userInfoStore_ using _let_, _Svelte_ will detect this and
> initialize it for us.

This is not bad, buuuuuut.... we can give it one more turn :), since we are using _$userInfoStore_
this is reactive a statement (tip $ prefix :)), why not just use it directly in our _html_:

```diff
<script lang="ts">
import { userInfoStore } from "./stores";
<script lang="ts">
import { userInfoStore } from "./stores";
- $: userInfo = $userInfoStore;
</script>
</script>

- <h2>User Logged in: {userInfo.name}</h2>
+ <h2>User Logged in: {$userInfoStore.username}</h2>
- <h2>User Logged in: {userInfo.name}</h2>
+ <h2>User Logged in: {$userInfoStore.username}</h2>
```

- Let's jump into the home page, in this page we got a button that toggles the user's name
Expand All @@ -359,36 +358,36 @@ How this could work:
_./src/pages/home-page.svelte_

```diff
<script lang="ts">
+ import { userInfoStore } from "../stores";
<script lang="ts">
+ import { userInfoStore } from "../stores";
+
let showLoggedInUser = false;
</script>

<div class="root">
<h1>Home page</h1>
<button
on:click={() => {
showLoggedInUser = !showLoggedInUser;
}}>Show Logged in User</button
>
{#if showLoggedInUser}
- <h2>Here we should show the logged in user</h2>
+ <h2>logged in user: {$userInfoStore.username}</h2>
{/if}
</div>
let showLoggedInUser = false;
</script>

<div class="root">
<h1>Home page</h1>
<button
on:click={() => {
showLoggedInUser = !showLoggedInUser;
}}>Show Logged in User</button
>
{#if showLoggedInUser}
- <h2>Here we should show the logged in user</h2>
+ <h2>logged in user: {$userInfoStore.username}</h2>
{/if}
</div>
```

- So far so good, but now let's go for a twist, we want to be able to update the user's name, from the home page, we can just bind
to _userInfo.username_

```diff
{#if showLoggedInUser}
<h2>logged in user: {$userInfoStore.username}</h2>
+ <input
+ bind:value={$userInfoStore.username}
+ />
{/if}
{#if showLoggedInUser}
<h2>logged in user: {$userInfoStore.username}</h2>
+ <input
+ bind:value={$userInfoStore.username}
+ />
{/if}
```

Let's give a try and YEEES... stores and reactive $ are our friends :).
Let's give a try and YEEES... stores and reactive _$_ are our friends :).
14 changes: 7 additions & 7 deletions 04-store-login/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion 04-store-login/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@sveltejs/vite-plugin-svelte": "^1.0.1",
"@tsconfig/svelte": "^3.0.0",
"prettier-plugin-svelte": "^2.7.0",
"svelte": "^3.49.0",
"svelte": "^3.50.1",
"svelte-check": "^2.8.0",
"svelte-preprocess": "^4.10.7",
"tslib": "^2.4.0",
Expand Down