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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Nina Torgunakova
October 31, 2023
Programming
1.1k
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
760
Unveiling Nano Stores
ninoid
0
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
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4.2k
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
880
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
360
Java × distroless で 軽量なコンテナイメージを / Java on Distroless
contour_gara
0
550
Spring Security 実践 ─ GraphQL APIで実務に役立つ 認証・認可 を学ぶ
wagyu
0
250
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
710
Performance Engineering for Everyone
elenatanasoiu
0
170
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
150
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
270
RTSPクライアントを自作してみた話
simotin13
0
610
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
190
Webフレームワークの ベンチマークについて
yusukebe
0
170
Featured
See All Featured
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.2k
Color Theory Basics | Prateek | Gurzu
gurzu
0
370
Making Projects Easy
brettharned
120
6.7k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
The Limits of Empathy - UXLibs8
cassininazir
1
360
Scaling GitHub
holman
464
140k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
220
The Language of Interfaces
destraynor
162
27k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
170
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