Tera Documentation
{
"config": {
"base_url": "/",
"mode": "build",
"title": "Phosphor",
"description": "Things we learned while building Phosphor",
"languages": {},
"default_language": "en",
"generate_feed": true,
"generate_feeds": true,
"feed_filenames": [
"atom.xml"
],
"taxonomies": [],
"author": null,
"build_search_index": true,
"extra": {
"logo_svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"108\" height=\"26\" fill=\"none\" viewBox=\"0 0 174 42\">\n<g fill=\"currentColor\">\n<path d=\"M.4 32.6c1.9 0 3-.9 3.8-3.9l4.6-22c.7-3-.7-4-2.5-4v-.5H19c9.2 0 11 5.5 10 10.1-1 4.8-4.8 9.5-16.5 9l.1-.5c7.3.4 10.5-3.9 11.3-8.4.9-4.3-.3-9.4-6.2-9.4h-3L9.2 28.7c-.7 3 1.2 3.9 3.7 3.9v.6H.5v-.6Z\"/><path d=\"M34.5 30.5c0-1.3.9-2.7 2.5-2.7 1.5 0 2.5 1.2 2.3 3-.2 1.2.3 1.6 1 1.5 1.7-.2 4.6-4.2 4.7-10.7 0-6.4-2-8.6-3.6-8.6-2.9 0-7.8 8-9.8 17.9l-.5 2.3h-4.7l5.7-27c.6-2.6 0-3.4-2-3.4v-.6c2.6-.2 5-.5 7.7-2.2l.3.3-.8 4-4 18.1C36 16 40 10 43.9 10c3.4 0 5.4 3.5 5.1 8.4-.3 6.2-4.8 15.2-10.8 15.2-2.4 0-3.6-1.6-3.6-3Zm15.9-9.2c1.6-7 7.4-11 12.6-11 5.2 0 9 5 7.3 12-1.6 7.2-7.4 11.3-12.5 11.3-5.5 0-9-5.2-7.4-12.3Zm7.9 11.5c2.7 0 5.6-4.1 7-11.1 1.4-7 .3-10.8-2.7-10.7-3 0-6 4.3-7.3 11.1-1.4 7 0 10.8 3 10.8Zm11.4-3.3c-.4-1.6.2-3 1.4-3.4a2.2 2.2 0 0 1 3 1.3c.5 1.4-.7 2.4-.6 3.8.2 1 1.2 1.9 3 1.8 1.8 0 3.5-1 4-3 .4-2-1-3.8-3.7-6.5-3-3-4.4-5.2-3.9-8.1.7-3 3.5-5.1 7.3-5.2 3-.1 5.9 1.2 6.5 3.6.5 1.5 0 3-1.4 3.4a2.1 2.1 0 0 1-2.8-1.3c-.5-1.6.8-2.5.6-3.5-.2-.9-1.1-1.7-2.6-1.6a3.8 3.8 0 0 0-3.7 3.2c-.2 1.7.5 3 3.1 5.5 2.7 2.6 5.2 5 4.5 8.5-.7 3.8-4 5.6-7.7 5.6-2.8 0-6.2-1.3-7-4.2Zm17.4 12c1.7 0 3-1 3-4v-22c0-2-.8-2.8-2.9-2.8V12c2.4-.2 5-.7 7.3-1.7l.4.2v4.6a7.7 7.7 0 0 1 7.1-4.8c5.3 0 9 5 9 11.4s-4.5 11.8-10.3 11.8A7.4 7.4 0 0 1 95 31v6.5c0 3 1.6 4 3.7 4v.5H87.1v-.6Zm13.3-8.7c3.3 0 5.7-3.7 5.7-9.4 0-6.9-3-10.5-6.5-10.5-2.4 0-4 1.6-4.7 3.7v7.6c0 4.8 2 8.6 5.5 8.6Z\"/><path d=\"M125 32.6c2.2 0 3.8-.9 3.4-3.9l-1.4-10c-.5-3.6-1.9-5.7-4.6-5.7-2.3 0-4 2.2-4.3 4.8v10.9c0 3 1.3 3.9 3 3.9v.6h-10.9v-.6c1.8 0 3.1-.8 3.1-3.9v-23c0-2.2-.9-3-2.9-3v-.5c2.3-.2 5-.6 7.3-1.7l.4.2V16c.8-3 3.3-5.6 6.7-5.6 3.7 0 6.2 2.5 7 8.2l1.5 10.2c.4 3 1.7 3.9 3.5 3.9v.5h-11.7v-.5ZM134.4 21.8a11 11 0 0 1 11.1-11.5c6 0 11.2 4.9 11.2 11.6 0 6.8-5 11.7-11 11.7-6.2 0-11.3-5.1-11.3-11.8Zm12.6 11c3.7-.6 5.3-5.7 4.5-12-.8-6-3.8-10.1-7.4-9.6-3.7.5-5.3 5.6-4.5 11.6.8 6.2 3.7 10.4 7.4 10Z\"/><path d=\"M155.9 32.6c1.8 0 3-.9 3-4v-13c0-2.2-.8-2.9-2.8-3v-.5a21.2 21.2 0 0 0 7.3-1.7l.4.2v4.8c.7-2.5 2.6-5 5.4-5 2.1 0 3.5 1.5 3.5 3.1 0 1.4-1 2.7-2.6 2.7s-2-1.4-2.4-2.3c-.3-.7-.5-1-1-1-1.4 0-2.7 2-3 4.2v11.6c0 3 1.8 3.9 4 3.9v.6H156v-.6Z\"/>\n</g>\n</svg>\n",
"drafts": true,
"sections": [
"Getting Started",
"Managing Complexity",
"Moving Quickly",
"Understanding Quickly",
"Architecture Patterns",
"Interactive Demos",
"Developer Tools",
"Advanced Topics"
],
"author": "Phosphor"
},
"markdown": {
"highlight_code": true,
"error_on_missing_highlight": false,
"highlight_theme": "base16-ocean-dark",
"highlight_themes_css": [],
"render_emoji": false,
"external_links_class": null,
"external_links_target_blank": false,
"external_links_no_follow": false,
"external_links_no_referrer": false,
"smart_punctuation": false,
"definition_list": false,
"bottom_footnotes": false,
"extra_syntaxes_and_themes": [],
"lazy_async_image": false,
"insert_anchor_links": "none",
"github_alerts": false
},
"search": {
"index_format": "elasticlunr_javascript"
},
"generate_sitemap": true,
"generate_robots_txt": true,
"exclude_paginated_pages_in_sitemap": "none"
},
"current_path": "/world-state-example/for-react-jotai/",
"current_url": "/world-state-example/for-react-jotai/",
"lang": "en",
"page": {
"relative_path": "world-state-example/for-react-jotai.md",
"colocated_path": null,
"content": "<h1 id=\"building-a-world-state\">Building a World State <div data-loc=\"content/world-state-example.md:12\" class=\"heading-src\">⋅</div></h1>\n<p>A world state is a reactive data structure that manages application state. In this article, we'll explore how to build a TodoMVC application using the view model pattern with LiveStore as our world state implementation.</p>\n<h2 id=\"interactive-demo\">Interactive Demo <div data-loc=\"content/world-state-example.md:16\" class=\"heading-src\">⋅</div></h2>\n<link rel=\"stylesheet\" href=\"/js/todo-vm.entrypoint.css\">\n<div data-loc=\"content/world-state-example.md:19\" id=\"todo-vm-demo\"></div>\n<script src=\"/js/todo-vm.entrypoint.js\" type=\"module\"></script>\n<h2 id=\"architecture-overview\">Architecture Overview <div data-loc=\"content/world-state-example.md:22\" class=\"heading-src\">⋅</div></h2>\n<p>This example uses React with LiveStore (an event-sourced reactive database) to manage application state. The view model pattern separates business logic from UI components.</p>\n<h2 id=\"creating-the-view-model\">Creating the View Model <div data-loc=\"content/world-state-example.md:26\" class=\"heading-src\">⋅</div></h2>\n<p>The view model (VM) defines the shape of our application's state and actions. Here's the TodoMVC VM structure:</p>\n<div class=\"codeblock\" data-loc=\"content/world-state-example.md:30\">\n \n <div class=\"codeblock-content\" data-id=\"todo-vm/scope.ts\">\n <pre class=\"shiki rose-pine\" style=\"background-color:#191724;color:#e0def4\" tabindex=\"0\" data-loc=\"content/_sources/view-model-interfaces/todo-vm/scope.ts:1\"><code><span class=\"line\"><span style=\"color:#31748F\">import </span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> computed</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> nanoid</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> queryDb</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> from </span><span style=\"color:#F6C177\">\"@livestore/livestore\"</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\">import type </span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> Queryable</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> Store</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> from </span><span style=\"color:#F6C177\">\"@livestore/livestore\"</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\">import </span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> DisposePool</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> dev</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> memoFn</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> from </span><span style=\"color:#F6C177\">\"@phosphor/utils\"</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\">import </span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> emitDebugValue</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> emitDebugValueFn</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> from </span><span style=\"color:#F6C177\">\"#scripts/lib/dev/emitDebugValue.ts\"</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\">import </span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> uiState$</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> from </span><span style=\"color:#F6C177\">\"./livestore/queries.js\"</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\">import </span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> events</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4;font-style:italic\"> tables</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#31748F\"> from </span><span style=\"color:#F6C177\">\"./livestore/schema.js\"</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\">export</span><span style=\"color:#31748F\"> type</span><span style=\"color:#9CCFD8\"> TodoItemVM</span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> key</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> text$</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Queryable</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">string</span><span style=\"color:#908CAA\">>;</span><span style=\"color:#E0DEF4\"> </span><span data-debug=\"!todo.text\"></span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> completed$</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Queryable</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">boolean</span><span style=\"color:#908CAA\">>;</span><span style=\"color:#E0DEF4\"> </span><span data-debug=\"!todo.completed\"></span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> toggleCompleted</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> void</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> remove</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> void</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">};</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\">export</span><span style=\"color:#31748F\"> type</span><span style=\"color:#9CCFD8\"> TodoListVM</span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> header</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> newTodoText$</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Queryable</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">string</span><span style=\"color:#908CAA\">>;</span><span style=\"color:#E0DEF4\"> </span><span data-debug=\"!newTodoText\"></span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> updateNewTodoText</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">text</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> void</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> addTodo</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> void</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> itemList</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> items$</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Queryable</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">TodoItemVM</span><span style=\"color:#E0DEF4\">[]</span><span style=\"color:#908CAA\">>;</span><span style=\"color:#E0DEF4\"> </span><span data-debug=\"!visibleTodos\"></span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> footer</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> incompleteCount$</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Queryable</span><span style=\"color:#908CAA\"><</span><span style=\"color:#9CCFD8\">number</span><span style=\"color:#908CAA\">>;</span><span style=\"color:#E0DEF4\"> </span><span data-debug=\"!incompleteCount\"></span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA;font-style:italic\"> currentFilter$</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Queryable</span><span style=\"color:#908CAA\"><</span><span style=\"color:#F6C177\">\"all\"</span><span style=\"color:#31748F\"> |</span><span style=\"color:#F6C177\"> \"active\"</span><span style=\"color:#31748F\"> |</span><span style=\"color:#F6C177\"> \"completed\"</span><span style=\"color:#908CAA\">>;</span><span style=\"color:#E0DEF4\"> </span><span data-debug=\"!currentFilter\"></span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> showAll</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> void</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> showActive</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> void</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> showCompleted</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> void</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> clearCompleted</span><span style=\"color:#31748F\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#9CCFD8\"> void</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">};</span></span>\n<span class=\"line\"></span>\n<span class=\"line muted\"><span style=\"color:#31748F\">const</span><span style=\"color:#EBBCBA;font-style:italic\"> createID</span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">name</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#F6C177\"> `</span><span style=\"color:#908CAA\">${</span><span style=\"color:#E0DEF4;font-style:italic\">name</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">_</span><span style=\"color:#908CAA\">${</span><span style=\"color:#EBBCBA\">nanoid</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#EBBCBA\">12</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">}</span><span style=\"color:#F6C177\">`</span><span style=\"color:#908CAA\">;</span><span style=\"color:#E0DEF4\"> </span></span>\n<span class=\"line\"><span style=\"color:#31748F\">export</span><span style=\"color:#31748F\"> function</span><span style=\"color:#EBBCBA\"> createTodoListScope</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">store</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> Store</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> TodoListVM</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> currentFilter$</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> computed</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">get</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#EBBCBA\"> get</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">uiState$</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">filter</span><span style=\"color:#908CAA\">,</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> label</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"filter\"</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> newTodoText$</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> computed</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">get</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#EBBCBA\"> get</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">uiState$</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">newTodoText</span><span style=\"color:#908CAA\">,</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> label</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"newTodoText\"</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> createTodoItemVM</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> memoFn</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">id</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> TodoItemVM</span><span style=\"color:#31748F\"> =></span><span style=\"color:#908CAA\"> {</span></span>\n<details class=\"code-fold\" data-fold-kind=\"indent\"><summary class=\"code-fold-summary\"><span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> completed$</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> queryDb</span><span style=\"color:#E0DEF4\">(</span></span><span class=\"code-fold-ellipsis\" aria-hidden=\"true\">[…]</span></summary><div class=\"code-fold-content\"><span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> tables</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">todos</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">select</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">\"completed\"</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">where</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> id</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">first</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> behaviour</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"error\"</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> label</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"todoItem.completed\"</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4\"> deps</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4\"> [</span><span style=\"color:#E0DEF4;font-style:italic\">id</span><span style=\"color:#E0DEF4\">] </span><span style=\"color:#908CAA\">},</span></span></div></details><span class=\"line\"><span style=\"color:#E0DEF4\"> )</span><span style=\"color:#908CAA\">;</span></span>\n<details class=\"code-fold\" data-fold-kind=\"indent\"><summary class=\"code-fold-summary\"><span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> text$</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> queryDb</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">tables</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">todos</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">select</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">\"text\"</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">where</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> id</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">first</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> behaviour</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"error\"</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span><span style=\"color:#908CAA\"> {</span></span><span class=\"code-fold-ellipsis\" aria-hidden=\"true\">[…]</span></summary><div class=\"code-fold-content\"><span class=\"line\"><span style=\"color:#E0DEF4\"> label</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"todoItem.text\"</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> deps</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4\"> [</span><span style=\"color:#E0DEF4;font-style:italic\">id</span><span style=\"color:#E0DEF4\">]</span><span style=\"color:#908CAA\">,</span></span></div></details><span class=\"line\"><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> key</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> id</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> completed$</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> text$</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> toggleCompleted</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">commit</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">query</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">completed$</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#31748F\">?</span><span style=\"color:#E0DEF4;font-style:italic\"> events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">todoUncompleted</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> id</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#31748F\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">todoCompleted</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> id</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> remove</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">commit</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">todoDeleted</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4;font-style:italic\"> id</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4\"> deletedAt</span><span style=\"color:#908CAA\">:</span><span style=\"color:#31748F\"> new</span><span style=\"color:#EBBCBA\"> Date</span><span style=\"color:#E0DEF4\">() </span><span style=\"color:#908CAA\">}</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#EBBCBA;font-style:italic\"> visibleTodosQuery</span><span style=\"color:#31748F\"> =</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">filter</span><span style=\"color:#31748F\">:</span><span style=\"color:#F6C177\"> \"all\"</span><span style=\"color:#31748F\"> |</span><span style=\"color:#F6C177\"> \"active\"</span><span style=\"color:#31748F\"> |</span><span style=\"color:#F6C177\"> \"completed\"</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> queryDb</span><span style=\"color:#E0DEF4\">(</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> tables</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">todos</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">where</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> completed</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> filter</span><span style=\"color:#31748F\"> ===</span><span style=\"color:#F6C177\"> \"all\"</span><span style=\"color:#31748F\"> ?</span><span style=\"color:#EBBCBA\"> undefined</span><span style=\"color:#31748F\"> :</span><span style=\"color:#E0DEF4;font-style:italic\"> filter</span><span style=\"color:#31748F\"> ===</span><span style=\"color:#F6C177\"> \"completed\"</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> deletedAt</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> op</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"=\"</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4\"> value</span><span style=\"color:#908CAA\">:</span><span style=\"color:#EBBCBA\"> null</span><span style=\"color:#908CAA\"> },</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> label</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"visibleTodos\"</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> map</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">rows</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#E0DEF4;font-style:italic\"> rows</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">map</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">(</span><span style=\"color:#C4A7E7;font-style:italic\">row</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#EBBCBA\"> createTodoItemVM</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">row</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">id</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> deps</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4\"> [</span><span style=\"color:#E0DEF4;font-style:italic\">filter</span><span style=\"color:#E0DEF4\">]</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> },</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> )</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<details class=\"code-fold\" data-fold-kind=\"indent\"><summary class=\"code-fold-summary\"><span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> visibleTodos$</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> computed</span><span style=\"color:#E0DEF4\">(</span></span><span class=\"code-fold-ellipsis\" aria-hidden=\"true\">[…]</span></summary><div class=\"code-fold-content\"><span class=\"line\"><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">get</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> filter</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> get</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">currentFilter$</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#EBBCBA\"> get</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#EBBCBA\">visibleTodosQuery</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">filter</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> },</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> {</span><span style=\"color:#E0DEF4\"> label</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"visibleTodos\"</span><span style=\"color:#908CAA\"> },</span></span></div></details><span class=\"line\"><span style=\"color:#E0DEF4\"> )</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> incompleteCount$</span><span style=\"color:#31748F\"> =</span><span style=\"color:#EBBCBA\"> queryDb</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">tables</span><span style=\"color:#31748F\">.</span><span style=\"color:#E0DEF4;font-style:italic\">todos</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">count</span><span style=\"color:#E0DEF4\">()</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">where</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> completed</span><span style=\"color:#908CAA\">:</span><span style=\"color:#EBBCBA\"> false</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4\"> deletedAt</span><span style=\"color:#908CAA\">:</span><span style=\"color:#EBBCBA\"> null</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> label</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"incompleteCount\"</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#31748F\"> return</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> header</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> newTodoText$</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> updateNewTodoText</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> (</span><span style=\"color:#C4A7E7;font-style:italic\">text</span><span style=\"color:#31748F\">:</span><span style=\"color:#9CCFD8\"> string</span><span style=\"color:#908CAA\">)</span><span style=\"color:#31748F\"> =></span><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">commit</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">uiStateSet</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> newTodoText</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> text</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> addTodo</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> const</span><span style=\"color:#E0DEF4;font-style:italic\"> newTodoText</span><span style=\"color:#31748F\"> =</span><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">query</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">newTodoText$</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">trim</span><span style=\"color:#E0DEF4\">()</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#31748F\"> if</span><span style=\"color:#E0DEF4\"> (</span><span style=\"color:#E0DEF4;font-style:italic\">newTodoText</span><span style=\"color:#E0DEF4\">) </span><span style=\"color:#908CAA\">{</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">commit</span><span style=\"color:#E0DEF4\">(</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">todoCreated</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> id</span><span style=\"color:#908CAA\">:</span><span style=\"color:#EBBCBA\"> createID</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#F6C177\">\"todo\"</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span><span style=\"color:#E0DEF4\"> text</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> newTodoText</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">uiStateSet</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> newTodoText</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"\"</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">)</span><span style=\"color:#908CAA\">,</span><span style=\"color:#908CAA;font-style:italic\"> //</span><span style=\"color:#6E6A86;font-style:italic\"> update text</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> )</span><span style=\"color:#908CAA\">;</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> }</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> },</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> },</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> itemList</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> items$</span><span style=\"color:#908CAA\">:</span><span style=\"color:#E0DEF4;font-style:italic\"> visibleTodos$</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> },</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4\"> footer</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> incompleteCount$</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#E0DEF4;font-style:italic\"> currentFilter$</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> showAll</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">commit</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">uiStateSet</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> filter</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"all\"</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> showActive</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">commit</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">uiStateSet</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> filter</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"active\"</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> showCompleted</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">commit</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">uiStateSet</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> filter</span><span style=\"color:#908CAA\">:</span><span style=\"color:#F6C177\"> \"completed\"</span><span style=\"color:#908CAA\"> }</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#EBBCBA\"> clearCompleted</span><span style=\"color:#908CAA\">:</span><span style=\"color:#908CAA\"> ()</span><span style=\"color:#31748F\"> =></span><span style=\"color:#E0DEF4;font-style:italic\"> store</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">commit</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#E0DEF4;font-style:italic\">events</span><span style=\"color:#31748F\">.</span><span style=\"color:#EBBCBA\">todoClearedCompleted</span><span style=\"color:#E0DEF4\">(</span><span style=\"color:#908CAA\">{</span><span style=\"color:#E0DEF4\"> deletedAt</span><span style=\"color:#908CAA\">:</span><span style=\"color:#31748F\"> new</span><span style=\"color:#EBBCBA\"> Date</span><span style=\"color:#E0DEF4\">() </span><span style=\"color:#908CAA\">}</span><span style=\"color:#E0DEF4\">))</span><span style=\"color:#908CAA\">,</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> },</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\"> };</span></span>\n<span class=\"line\"><span style=\"color:#908CAA\">}</span></span>\n<span class=\"line\"></span></code></pre>\n </div>\n \n</div>\n<h2 id=\"wiring-the-view-model-to-react\">Wiring the View Model to React <div data-loc=\"content/world-state-example.md:32\" class=\"heading-src\">⋅</div></h2>\n<p>The Root component sets up the LiveStore provider and creates the view model:</p>\n<pre data-lang=\"tsx\" style=\"background-color:#2b303b;color:#c0c5ce;\" class=\"language-tsx \"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"color:#b48ead;\">import </span><span>{ </span><span style=\"color:#bf616a;\">LiveStoreProvider</span><span>, </span><span style=\"color:#bf616a;\">useStore </span><span>} </span><span style=\"color:#b48ead;\">from </span><span>"</span><span style=\"color:#a3be8c;\">@livestore/react</span><span>";\n</span><span style=\"color:#b48ead;\">import </span><span>{ </span><span style=\"color:#bf616a;\">createContext</span><span>, </span><span style=\"color:#bf616a;\">useContext</span><span>, </span><span style=\"color:#bf616a;\">useMemo </span><span>} </span><span style=\"color:#b48ead;\">from </span><span>"</span><span style=\"color:#a3be8c;\">react</span><span>";\n</span><span>\n</span><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">TodoVMContext </span><span>= </span><span style=\"color:#8fa1b3;\">createContext</span><span><TodoListVM | null>(</span><span style=\"color:#d08770;\">null</span><span>);\n</span><span>\n</span><span style=\"color:#b48ead;\">export const </span><span style=\"color:#8fa1b3;\">useTodoVM </span><span>= () </span><span style=\"color:#b48ead;\">=> </span><span>{\n</span><span> </span><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">vm </span><span>= </span><span style=\"color:#8fa1b3;\">useContext</span><span>(</span><span style=\"color:#bf616a;\">TodoVMContext</span><span>);\n</span><span> </span><span style=\"color:#b48ead;\">if </span><span>(!</span><span style=\"color:#bf616a;\">vm</span><span>) </span><span style=\"color:#b48ead;\">throw </span><span>new Error("</span><span style=\"color:#a3be8c;\">useTodoVM must be used within TodoVMProvider</span><span>");\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span style=\"color:#bf616a;\">vm</span><span>;\n</span><span>};\n</span><span>\n</span><span style=\"color:#b48ead;\">const </span><span style=\"color:#8fa1b3;\">TodoVMProvider</span><span>: React.FC<{ </span><span style=\"color:#bf616a;\">children</span><span>: React.ReactNode }> = ({ </span><span style=\"color:#bf616a;\">children </span><span>}) </span><span style=\"color:#b48ead;\">=> </span><span>{\n</span><span> </span><span style=\"color:#b48ead;\">const </span><span>{ </span><span style=\"color:#bf616a;\">store </span><span>} = </span><span style=\"color:#8fa1b3;\">useStore</span><span>();\n</span><span> </span><span style=\"color:#b48ead;\">const </span><span style=\"color:#bf616a;\">vm </span><span>= </span><span style=\"color:#8fa1b3;\">useMemo</span><span>(() </span><span style=\"color:#b48ead;\">=> </span><span style=\"color:#8fa1b3;\">createTodoListScope</span><span>(</span><span style=\"color:#bf616a;\">store</span><span>), [</span><span style=\"color:#bf616a;\">store</span><span>]);\n</span><span> </span><span style=\"color:#b48ead;\">return </span><span><</span><span style=\"color:#ebcb8b;\">TodoVMContext.Provider </span><span style=\"color:#d08770;\">value</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">vm</span><span style=\"color:#ab7967;\">}</span><span>></span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">children</span><span style=\"color:#ab7967;\">}</span><span></</span><span style=\"color:#ebcb8b;\">TodoVMContext.Provider</span><span>>;\n</span><span>};\n</span><span>\n</span><span style=\"color:#b48ead;\">export const </span><span style=\"color:#8fa1b3;\">App</span><span>: React.FC = () </span><span style=\"color:#b48ead;\">=> </span><span>(\n</span><span> <</span><span style=\"color:#ebcb8b;\">LiveStoreProvider\n</span><span> </span><span style=\"color:#d08770;\">schema</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">schema</span><span style=\"color:#ab7967;\">}\n</span><span> </span><span style=\"color:#d08770;\">adapter</span><span>=</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">adapter</span><span style=\"color:#ab7967;\">}\n</span><span> </span><span style=\"color:#d08770;\">renderLoading</span><span>=</span><span style=\"color:#ab7967;\">{</span><span>(</span><span style=\"color:#bf616a;\">state</span><span>) </span><span style=\"color:#b48ead;\">=> </span><span><</span><span style=\"color:#bf616a;\">div</span><span>>Loading LiveStore (</span><span style=\"color:#ab7967;\">{</span><span style=\"color:#bf616a;\">state</span><span>.</span><span style=\"color:#bf616a;\">stage</span><span style=\"color:#ab7967;\">}</span><span>)...</</span><span style=\"color:#bf616a;\">div</span><span>></span><span style=\"color:#ab7967;\">}\n</span><span> >\n</span><span> <</span><span style=\"color:#ebcb8b;\">TodoVMProvider</span><span>>\n</span><span> <</span><span style=\"color:#bf616a;\">section </span><span style=\"color:#d08770;\">className</span><span>="</span><span style=\"color:#a3be8c;\">todos</span><span>">\n</span><span> <</span><span style=\"color:#ebcb8b;\">Header </span><span>/>\n</span><span> <</span><span style=\"color:#ebcb8b;\">MainSection </span><span>/>\n</span><span> <</span><span style=\"color:#ebcb8b;\">Footer </span><span>/>\n</span><span> </</span><span style=\"color:#bf616a;\">section</span><span>>\n</span><span> </</span><span style=\"color:#ebcb8b;\">TodoVMProvider</span><span>>\n</span><span> </</span><span style=\"color:#ebcb8b;\">LiveStoreProvider</span><span>>\n</span><span>);\n</span></code></pre>\n<p>The key concept is that all components share the same view model instance through React Context. The view model is created once when the store is initialized, and components subscribe to reactive queries that automatically re-render when data changes.</p>\n<p><strong>Key patterns:</strong></p>\n<ul>\n<li><strong>Single source of truth</strong>: The LiveStore holds all application state</li>\n<li><strong>Reactive queries</strong>: Components use <code>Queryable<T></code> to subscribe to data</li>\n<li><strong>Action methods</strong>: View model exposes methods that commit events to the store</li>\n<li><strong>Separation of concerns</strong>: Business logic lives in the view model, not in components</li>\n</ul>\n",
"permalink": "/world-state-example/for-react-jotai/",
"slug": "for-react-jotai",
"ancestors": [],
"title": "Building a World State",
"description": null,
"updated": null,
"date": "2025-10-15",
"year": 2025,
"month": 10,
"day": 15,
"taxonomies": {},
"authors": [],
"extra": {
"nav_section": "Architecture Patterns",
"nav_order": 2,
"substitution": "react-jotai"
},
"path": "/world-state-example/for-react-jotai/",
"components": [
"world-state-example",
"for-react-jotai"
],
"summary": null,
"toc": [
{
"level": 1,
"id": "building-a-world-state",
"permalink": "/world-state-example/for-react-jotai/#building-a-world-state",
"title": "Building a World State ⋅",
"children": [
{
"level": 2,
"id": "interactive-demo",
"permalink": "/world-state-example/for-react-jotai/#interactive-demo",
"title": "Interactive Demo ⋅",
"children": []
},
{
"level": 2,
"id": "architecture-overview",
"permalink": "/world-state-example/for-react-jotai/#architecture-overview",
"title": "Architecture Overview ⋅",
"children": []
},
{
"level": 2,
"id": "creating-the-view-model",
"permalink": "/world-state-example/for-react-jotai/#creating-the-view-model",
"title": "Creating the View Model ⋅",
"children": []
},
{
"level": 2,
"id": "wiring-the-view-model-to-react",
"permalink": "/world-state-example/for-react-jotai/#wiring-the-view-model-to-react",
"title": "Wiring the View Model to React ⋅",
"children": []
}
]
}
],
"word_count": 295,
"reading_time": 2,
"assets": [],
"draft": true,
"lang": "en",
"lower": null,
"higher": null,
"translations": [],
"backlinks": []
},
"zola_version": "0.21.0"
}