Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Smart nano stores for state management, or how ...
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
840
Unveiling Nano Stores
ninoid
0
1.1k
Умные nano stores, или как мы сделали веб-разработку проще
ninoid
0
1k
Solving algorithms: beyond cramming for job interviews
ninoid
0
2.4k
Other Decks in Programming
See All in Programming
How I Stole PSI from Android Studio - DroidKaigi2026
worker8
0
110
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
160
ソフトウェアラスタライザ
fadis
1
800
MIZARU@SPAJAM2026 第二回予選
1901drama
0
110
Can LLMs Replicate 4 Years of Compose Migration? Exploring the boundaries of automation with 279 XML files from a real product
makun
0
130
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
160
iOSDC2026登壇資料.pdf
riofujimon
0
110
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
3
530
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
240
GKE アップグレード前に知っておきたい Blue/Green と PDB の関係
stkk
0
160
ハーネス設計入門 〜プロンプト、コンテキストの次〜
kinopeee
56
38k
Webの地図
yosuke_furukawa
PRO
6
4.1k
Featured
See All Featured
Un-Boring Meetings
codingconduct
0
410
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.5k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
820
Fashionably flexible responsive web design (full day workshop)
malarkey
408
67k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
830
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
A Tale of Four Properties
chriscoyier
163
24k
Making Projects Easy
brettharned
120
6.7k
How STYLIGHT went responsive
nonsquared
100
6.3k
Are puppies a ranking factor?
jonoalderson
2
3.9k
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