Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Smart nano stores for state management, or how ...
Search
Nina Torgunakova
October 31, 2023
Programming
1.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Smart nano stores for state management, or how we made front-end simpler
Nina Torgunakova
October 31, 2023
More Decks by Nina Torgunakova
See All by Nina Torgunakova
Smart Nano Stores, or how we made front-end simpler (for the FOF meetup in Lisbon)
ninoid
1
820
Unveiling Nano Stores
ninoid
0
1.1k
Умные nano stores, или как мы сделали веб-разработку проще
ninoid
0
1k
Solving algorithms: beyond cramming for job interviews
ninoid
0
2.3k
Other Decks in Programming
See All in Programming
typoなんかねぇよ
raspython3
0
620
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
5
1.8k
異なる設計思想のフレームワークを経験して得た学び
amekuhideki
2
850
AWS Transform Customによる Spring Boot 2.xから4.xへのVerUp
satoshi256kbyte
2
110
Claude Code全社展開のためにやったことn選~プラグイン302個・コミッター271人を支えるために~
kenchan
5
1.8k
tsc.rip を支える技術 / Kyoto.なんか #8
susisu
0
3.9k
My Marp Sample
sinoue0108
0
130
【QA Test Talk Vol.8】AI-DLC による Whole Team Approach の加速
pkshadeck
PRO
0
250
「人を評価する AI」の設計と実装
ryoyanara
0
260
AIに既存システムを理解させる技術 ~レガシーを見捨てないハーネスエンジニアリング入門~
ochtum
0
170
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
800
TSX の <Hoge<Fuga>> という構文に驚いた話 / tsx-type-argument-syntax
kanaru0928
0
240
Featured
See All Featured
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
400
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
Ruling the World: When Life Gets Gamed
codingconduct
0
310
Between Models and Reality
mayunak
4
410
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
400
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
590
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.2k
Become a Pro
speakerdeck
PRO
31
6.2k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Balancing Empowerment & Direction
lara
6
1.3k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.1k
Transcript
1
Smart nano stores for state management 2 @evilmartians or how
we made front-end simpler
Nina Torgunakova Frontend Engineer 3 @evilmartians
4 Simplicity of HTML + CSS + JS @evilmartians
5 What we had before @evilmartians
6 @evilmartians
7 What we have today * Source: www.medium.com/@withinsight1/the-front-end-spectrum-c0f30998c9f0/ @evilmartians
8 @evilmartians
The modern Web Development World is becoming more and more
complex. Who suffers from it? 9 @evilmartians
1. Developers 10 @evilmartians
11 Everything is built around frameworks but remains complex @evilmartians
We need a lot of actions to make something simple.
12 But the most crucial: @evilmartians
2. Users 13 @evilmartians
14 * Source: www.keycdn.com/support/the-growth-of-web-page-size @evilmartians
15 * Source: www.hobo-web.co.uk/your-website-design-should-load-in-4-seconds/ @evilmartians
16 The more complex and confusing a code, the more
likely a user is to encounter bugs @evilmartians
3. Business 17 @evilmartians
18 Sometimes, to do the same amount of work, more
programmers are needed. Now Before @evilmartians
19 As a result, both time and money are wasted.
@evilmartians
20 Result: the growing complexity of Web Development makes everyone
frustrated. Users Developers Business @evilmartians
21 Simplicity is a key What can we do for
the first step? @evilmartians
22 Let's try to find inspiration! @evilmartians
Fold knowledge into data, so program logic can be stupid
and robust. 23 Eric Raymond, “Rule of Representation” @evilmartians
Now development revolves around frameworks 24 @evilmartians
25 Framework Logic UI Features Data @evilmartians
But what if we made a mistake? 26 @evilmartians
27
None
We also can change our model and fold knowledge into
data, and not the framework. 29 @evilmartians
30 Data Logic UI Features Framework Logic UI Features Data
Framework @evilmartians
State Management 31 Application Data State @evilmartians
32 Use stores to move logic outside of components Component
Component Component Store Store @evilmartians
OK, any other ideas about the ideal process of state
management? 33 @evilmartians
Bad programmers worry about the code. Good programmers worry about
data structures and their relationships. 34 Linus Torvalds @evilmartians
35 Global State Any State Change All Components Call the
selector function Popular global state approach: @evilmartians
36 How about improving data structure and making it faster?
@evilmartians
37 Reactive programming approach: @evilmartians
38 Applying to State Management: Component Component Component Subscriber 1
Subscriber 2 Subscriber 3 Small Store Small Store Small Store @evilmartians
39 Small Store State Change Subscribed components Receive changed value
Small Store State Change Subscribed components Receive changed value Only subscribed components receive changes from needed stores: @evilmartians
40 But what if some data depends on other data?
@evilmartians
41 Solution: Relationships between stores Store Store Store Store @evilmartians
42 Chains of reactive computations Component Component Store Store Store
@evilmartians
1. Move logic to stores outside of component 2. Make
stores small and smart Let's go further! 43 @evilmartians
Perfection is achieved, not when there is nothing more to
add, but when there is nothing left to take away. 44 Antoine de Saint-Exupéry @evilmartians
45 State Management in modern frameworks: @evilmartians
46 Smart Store Set value Get value @evilmartians
Stores can be smart. But the process should be simple
and minimalistic. 47 @evilmartians
1. Move logic to stores outside of components 2. Make
stores small and smart 3. Provide minimalism and simplicity One more thing! 48 @evilmartians
Everything should be made as simple as possible, but no
simpler. 49 Albert Einstein @evilmartians
We want some simple way; but not oversimplified. 50 @evilmartians
We need to consider many different challenges: - Synchronizing changes
between browser tabs - Implementing SPA navigation - Automatic translation of content - Conflict resolution …and more… 51 @evilmartians
No mental overload for hard cases 52 No boilerplate for
easy cases @evilmartians
53 Making complex things simple to understand @evilmartians
54 Let's summarize! @evilmartians
1. Move logic to stores outside of components. 55 Component
Component Component Store Store @evilmartians
2. Make stores small and smart. 56 Store Store Store
Store Store @evilmartians
3. Provide minimalism and simplicity. 57 Store One-line operations: •
Create store • Get value • Set value Get value Set value @evilmartians
4. Consider developer challenges. 58 SPA Navigation Smart data fetching
Automatic Translations Conflict resolution Synchronizing @evilmartians
59 ??? What state manager will solve all the problems?
@evilmartians
60 Nano Stores @evilmartians
Let's build a simple online shop: 61 @evilmartians
62 @evilmartians
63 @evilmartians
Creating atom store for products in catalog: // core/state.ts import
{ atom } from 'nanostores'; export const $products = atom<Product[]>([ { name: 'Nano Phone', price: 30 }, { name: 'Nano TV', price: 75 }, { name: 'Nano Laptop' , price: 75 } ]); 64 @evilmartians
Using atom store: // components/Catalog.tsx import { $products } from
'core/state'; import { useStore } from '@nanostores/react' ; const Catalog = () => { const products = useStore($products); return <>{products.map((product) => <Card product={product} />)}</>; }; 65 @evilmartians
66 @evilmartians
Adding filtering using search input 67 @evilmartians
Creating atom store for search input: // core/state.ts import {
atom } from 'nanostores'; export const $searchInput = atom<string>(''); 68 @evilmartians
Using atom store for search input: // components/SearchBar.tsx import {
$searchInput } from 'core/state'; import { useStore } from '@nanostores/react' ; const SearchBar = () => { const searchInput = useStore($searchInput); return <input onChange={(e) => $searchInput.set(e.target.value) } value={searchInput} /> ; }; 69 @evilmartians
Adding computed store to filter catalog: // core/state.ts import {
computed } from 'nanostores'; const $filteredProducts = computed( [$searchInput, $products], ( searchInput, products) => { return products.filter(product => product.name.includes(searchInput)); } ); 70 @evilmartians
Using computed store in components: // components/Catalog.tsx import { useStore
} from '@nanostores/react' ; import { $filteredProducts } from 'core/state'; // Usage is exactly the same: const Catalog = () => { const filteredProducts = useStore($filteredProducts); return <>{filteredProducts. map((product) => <Card product={product} />)}</>; }; 71 @evilmartians
72 @evilmartians
73 Nano Stores Query A tiny data fetcher for Nano
Stores. @evilmartians
Define Fetcher Context: // core/fetcher.ts import { nanoquery } from
'@nanostores/query' ; export const [createFetcherStore ] = nanoquery({ fetcher: (...keys: string[]) => fetch(keys.join('')).then((r) => r.json()), }); 74 @evilmartians
Create Fetcher Store using context: // core/state.ts import { createFetcherStore
} from 'core/fetcher' ; export const $fetchedProducts = createFetcherStore (['products']); 75 @evilmartians
Using Fetcher Store: // components/Catalog.tsx import { useStore } from
'@nanostores/react' ; import { $fetchedProducts } from 'core/state'; const Catalog = () => { const { data, error, loading } = useStore($fetchedProducts); if (loading) return <Spinner/>; if (error) return <>Error!</>; return <>{data.content. map((product) => <Card product={product} />)}</>; }; 76 @evilmartians
77 @evilmartians
78 @evilmartians
More customization for fetching: // core/fetcher.ts const [createFetcherStore ] =
nanoquery({ fetcher: (...keys: string[]) => fetch(keys.join('')).then((r) => r.json()), refetchInterval : 30000, // revalidate cache on an interval, ms refetchOnFocus : true, // revalidate cache when the window focuses refetchOnReconnect : true, // revalidate cache when network connection restores }); 79 @evilmartians
80 @evilmartians
81 Nano Stores Router A tiny URL router for Nano
Stores. @evilmartians
Create router store: // core/router.ts import { createRouter } from
'@nanostores/router'; export const $router = createRouter({ catalog: '/catalog', cart: '/cart', ... }); 82 @evilmartians
Using router store: // components/Router.tsx import { $router } from
'core/router' ; const Router = () => { const router = useStore($router); switch (router?.route) { case 'catalog': return <CatalogPage />; case 'cart': return <CartPage />; ... } } 83 @evilmartians
Subscribing to store's changes: // core/router.ts import { atom }
from 'nanostores' ; const $headerName = atom(''); $router.subscribe((newRouterValue ) => { let header = 'Nano Shop' ; switch (newRouterValue ?.route) { case 'catalog': header = 'Nano Shop Catalog'; case 'cart': header = 'Nano Shop Cart'; ... } $headerName .set(header); document.title = header; }); 84 @evilmartians
Using current value in component: // components/Header.tsx import { useStore
} from '@nanostores/react' ; import { $headerName } from 'core/router' ; export const Header = () => { const headerName = useStore($headerName); return <header>{headerName}</header>; }; 85 @evilmartians
86 @evilmartians
87 @evilmartians
88 Nano Stores Persistent A tiny store for local storage.
@evilmartians
Keep cart items in the LocalStorage key: import { persistentAtom
} from '@nanostores/persistent'; export const $shoppingCart = persistentAtom<Product[]>('cart', [], { encode: JSON.stringify, decode: JSON.parse, }); 89 @evilmartians
Change store value: // Adding newProduct to Persistent Map store:
export const addProductToCart = (newProduct: Product) => { $shoppingCart .set([...$shoppingCart .get(), newProduct]); }; 90 @evilmartians
91 @evilmartians
92 Store changes are synchronized between browser tabs by default:
@evilmartians
93 Testing Nano Stores @evilmartians
afterEach(() => { $shoppingCart .set([]); }); it("should add product to
cart" , () => { $shoppingCart .listen(() => {}); addProductToCart ({ name: "Nano Tablet" , price: 50 }); expect($shoppingCart .get().length).toEqual(1); }); 94 No need to emulate DOM: @evilmartians
95 Nano Stores atom code in 84 lines: @evilmartians
So, what is next? 1. Try out a new approach
to state management in your own project. 2. See the power of simplicity! 96 github.com/nanostores @evilmartians
97 Questions? @evilmartians