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
810
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
Apache Hive: そしてCloud Native Lakehouseへ
okumin
1
210
5分で問診!Composer セキュリティ健康診断
codmoninc
0
910
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
3.6k
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
1.7k
Foundation Models frameworkで画像分析
ryodeveloper
1
600
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
4
380
仕様駆動開発の消費期限
watany
17
7.4k
言語を使う側から、作る側へ。 自作 Lisp で得た新たな気づき。
andpad
0
160
VibeCodingからAgenticWorkflowへ
starfish719
0
330
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
210
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
160
プロポーザルを書いてもらう
pvcresin
0
290
Featured
See All Featured
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.2k
We Are The Robots
honzajavorek
0
290
Java REST API Framework Comparison - PWX 2021
mraible
34
9.6k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
240
[SF Ruby Conf 2025] Rails X
palkan
2
1.3k
Producing Creativity
orderedlist
PRO
348
40k
How STYLIGHT went responsive
nonsquared
100
6.2k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
420
ラッコキーワード サービス紹介資料
rakko
1
4.3M
Color Theory Basics | Prateek | Gurzu
gurzu
0
410
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
270
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