[{"data":1,"prerenderedAt":34467},["ShallowReactive",2],{"navigation_docs":3,"-react-native-version2-redux-toolkit-on-mobile":3728,"-react-native-version2-redux-toolkit-on-mobile-surround":34462},[4,1707,1912,2366,2547,2673,2880,3002,3052,3109,3143,3269,3346,3360,3495,3512,3525,3671,3724],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"Робота з файлами: C-стиль (stdio.h)","\u002Fcpp\u002Fc-style-files","02.cpp\u002F47.c-style-files",{"title":1905,"path":1906,"stem":1907},"Робота з файлами: C++-стиль (fstream)","\u002Fcpp\u002Fcpp-style-files","02.cpp\u002F48.cpp-style-files",{"title":1909,"path":1910,"stem":1911},"План навчання: Курс C++ — Продовження (Статті 29–60+)","\u002Fcpp\u002Fcurriculum-plan","02.cpp\u002Fcurriculum-plan",{"title":1913,"icon":1914,"path":1915,"stem":1916,"children":1917,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[1918,1944,1998,2020,2324,2362],{"title":1919,"icon":1920,"path":1921,"stem":1922,"children":1923,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[1924,1928,1932,1936,1940],{"title":1925,"path":1926,"stem":1927},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":1929,"path":1930,"stem":1931},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":1933,"path":1934,"stem":1935},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":1937,"path":1938,"stem":1939},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":1941,"path":1942,"stem":1943},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":1945,"icon":1946,"path":1947,"stem":1948,"children":1949,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[1950,1954,1958,1962,1966,1970,1974,1978,1982,1986,1990,1994],{"title":1951,"path":1952,"stem":1953},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":1955,"path":1956,"stem":1957},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":1959,"path":1960,"stem":1961},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":1963,"path":1964,"stem":1965},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":1967,"path":1968,"stem":1969},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":1971,"path":1972,"stem":1973},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":1975,"path":1976,"stem":1977},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":1979,"path":1980,"stem":1981},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":1983,"path":1984,"stem":1985},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":1987,"path":1988,"stem":1989},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":1991,"path":1992,"stem":1993},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":1995,"path":1996,"stem":1997},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":1999,"icon":2000,"path":2001,"stem":2002,"children":2003,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[2004,2008,2012,2016],{"title":2005,"path":2006,"stem":2007},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2009,"path":2010,"stem":2011},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2013,"path":2014,"stem":2015},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2017,"path":2018,"stem":2019},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2021,"icon":2022,"path":2023,"stem":2024,"children":2025},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2026,2027,2031,2035,2039,2043,2106,2141,2293],{"title":2021,"path":2023,"stem":2024},{"title":2028,"path":2029,"stem":2030},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2032,"path":2033,"stem":2034},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2036,"path":2037,"stem":2038},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2040,"path":2041,"stem":2042},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2044,"icon":132,"path":2045,"stem":2046,"children":2047},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2048,2050,2054,2058,2062,2066,2070,2074,2078,2082,2086,2090,2094,2098,2102],{"title":2049,"path":2045,"stem":2046},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2051,"path":2052,"stem":2053},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2055,"path":2056,"stem":2057},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2059,"path":2060,"stem":2061},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2063,"path":2064,"stem":2065},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2067,"path":2068,"stem":2069},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2071,"path":2072,"stem":2073},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2075,"path":2076,"stem":2077},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2079,"path":2080,"stem":2081},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2083,"path":2084,"stem":2085},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2087,"path":2088,"stem":2089},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2091,"path":2092,"stem":2093},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2095,"path":2096,"stem":2097},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2099,"path":2100,"stem":2101},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2103,"path":2104,"stem":2105},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2107,"icon":2022,"path":2108,"stem":2109,"children":2110},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2111,2113,2117,2121,2125,2129,2133,2137],{"title":2112,"path":2108,"stem":2109},"React Router: Навігаційна система сучасного вебу",{"title":2114,"path":2115,"stem":2116},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2118,"path":2119,"stem":2120},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2122,"path":2123,"stem":2124},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2126,"path":2127,"stem":2128},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2130,"path":2131,"stem":2132},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2134,"path":2135,"stem":2136},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2138,"path":2139,"stem":2140},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2142,"icon":132,"path":2143,"stem":2144,"children":2145},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2146,2148,2164,2193,2202,2223,2239,2268],{"title":2147,"path":2143,"stem":2144},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2149,"stem":2150,"children":2151,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2152,2156,2160],{"title":2153,"path":2154,"stem":2155},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2157,"path":2158,"stem":2159},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2161,"path":2162,"stem":2163},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2165,"icon":132,"path":2166,"stem":2167,"children":2168,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2169,2173,2177,2181,2185,2189],{"title":2170,"path":2171,"stem":2172},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2174,"path":2175,"stem":2176},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2178,"path":2179,"stem":2180},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2182,"path":2183,"stem":2184},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2186,"path":2187,"stem":2188},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2190,"path":2191,"stem":2192},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2194,"icon":132,"path":2195,"stem":2196,"children":2197,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2198],{"title":2199,"path":2200,"stem":2201},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2203,"icon":132,"path":2204,"stem":2205,"children":2206,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2207,2211,2215,2219],{"title":2208,"path":2209,"stem":2210},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2212,"path":2213,"stem":2214},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2216,"path":2217,"stem":2218},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2220,"path":2221,"stem":2222},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2224,"icon":92,"path":2225,"stem":2226,"children":2227,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2228,2232,2236],{"title":2229,"path":2230,"stem":2231},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2233,"path":2234,"stem":2235},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2083,"path":2237,"stem":2238},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2240,"icon":132,"path":2241,"stem":2242,"children":2243,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2244,2248,2252,2256,2260,2264],{"title":2245,"path":2246,"stem":2247},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2249,"path":2250,"stem":2251},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2253,"path":2254,"stem":2255},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2257,"path":2258,"stem":2259},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2261,"path":2262,"stem":2263},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2265,"path":2266,"stem":2267},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2269,"icon":132,"path":2270,"stem":2271,"children":2272,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2273,2277,2281,2285,2289],{"title":2274,"path":2275,"stem":2276},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2278,"path":2279,"stem":2280},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2282,"path":2283,"stem":2284},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2286,"path":2287,"stem":2288},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2290,"path":2291,"stem":2292},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2294,"icon":132,"path":2295,"stem":2296,"children":2297},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2298,2300,2304,2308,2312,2316,2320],{"title":2299,"path":2295,"stem":2296},"UI Бібліотеки в React",{"title":2301,"path":2302,"stem":2303},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2305,"path":2306,"stem":2307},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2309,"path":2310,"stem":2311},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2313,"path":2314,"stem":2315},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2317,"path":2318,"stem":2319},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2321,"path":2322,"stem":2323},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2325,"icon":2326,"path":2327,"stem":2328,"children":2329,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2330,2334,2338,2342,2346,2350,2354,2358],{"title":2331,"path":2332,"stem":2333},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2335,"path":2336,"stem":2337},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2339,"path":2340,"stem":2341},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2343,"path":2344,"stem":2345},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2347,"path":2348,"stem":2349},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2351,"path":2352,"stem":2353},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2355,"path":2356,"stem":2357},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2359,"path":2360,"stem":2361},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2363,"path":2364,"stem":2365},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2367,"icon":2368,"path":2369,"stem":2370,"children":2371,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2372,2375,2378,2382,2386,2390,2394],{"title":162,"path":2373,"stem":2374},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2376,"stem":2377},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2379,"path":2380,"stem":2381},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2383,"path":2384,"stem":2385},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2387,"path":2388,"stem":2389},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2391,"path":2392,"stem":2393},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2395,"path":2396,"stem":2397,"children":2398,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2399,2403,2407,2411,2415,2419,2423,2427,2431,2435,2439,2443,2447,2451,2455,2459,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511,2515,2519,2523,2527,2531,2535,2539,2543],{"title":2400,"path":2401,"stem":2402},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2404,"path":2405,"stem":2406},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2408,"path":2409,"stem":2410},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2412,"path":2413,"stem":2414},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2416,"path":2417,"stem":2418},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2420,"path":2421,"stem":2422},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2424,"path":2425,"stem":2426},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2428,"path":2429,"stem":2430},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2432,"path":2433,"stem":2434},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2436,"path":2437,"stem":2438},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2440,"path":2441,"stem":2442},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2444,"path":2445,"stem":2446},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2448,"path":2449,"stem":2450},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2452,"path":2453,"stem":2454},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2456,"path":2457,"stem":2458},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2460,"path":2461,"stem":2462},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2464,"path":2465,"stem":2466},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2468,"path":2469,"stem":2470},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2472,"path":2473,"stem":2474},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2476,"path":2477,"stem":2478},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2480,"path":2481,"stem":2482},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2484,"path":2485,"stem":2486},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2488,"path":2489,"stem":2490},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2492,"path":2493,"stem":2494},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2496,"path":2497,"stem":2498},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2500,"path":2501,"stem":2502},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2504,"path":2505,"stem":2506},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2508,"path":2509,"stem":2510},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2512,"path":2513,"stem":2514},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2516,"path":2517,"stem":2518},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2520,"path":2521,"stem":2522},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2524,"path":2525,"stem":2526},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2528,"path":2529,"stem":2530},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2532,"path":2533,"stem":2534},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2536,"path":2537,"stem":2538},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2540,"path":2541,"stem":2542},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2544,"path":2545,"stem":2546},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2548,"icon":2549,"path":2550,"stem":2551,"children":2552,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2553,2557,2560,2564,2568,2572,2576,2580,2584,2588,2592,2596,2600,2604,2608,2669],{"title":2554,"path":2555,"stem":2556},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2558,"stem":2559},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2561,"path":2562,"stem":2563},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2565,"path":2566,"stem":2567},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2569,"path":2570,"stem":2571},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2573,"path":2574,"stem":2575},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2577,"path":2578,"stem":2579},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2581,"path":2582,"stem":2583},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2585,"path":2586,"stem":2587},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2589,"path":2590,"stem":2591},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2593,"path":2594,"stem":2595},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2597,"path":2598,"stem":2599},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2601,"path":2602,"stem":2603},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2605,"path":2606,"stem":2607},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2609,"icon":92,"path":2610,"stem":2611,"children":2612,"page":59},"FastAPI","\u002Fpython\u002Ffastapi","05.python\u002Ffastapi",[2613,2617,2621,2625,2629,2633,2637,2641,2645,2649,2653,2657,2661,2665],{"title":2614,"path":2615,"stem":2616},"Глибокий Typing та Pydantic v2 — від анотацій до валідації","\u002Fpython\u002Ffastapi\u002Ftyping-pydantic","05.python\u002Ffastapi\u002F15.typing-pydantic",{"title":2618,"path":2619,"stem":2620},"WSGI, ASGI та Python Web-екосистема","\u002Fpython\u002Ffastapi\u002Fwsgi-asgi-ecosystem","05.python\u002Ffastapi\u002F16.wsgi-asgi-ecosystem",{"title":2622,"path":2623,"stem":2624},"FastAPI: Перший додаток, Uvicorn та OpenAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-intro","05.python\u002Ffastapi\u002F17.fastapi-intro",{"title":2626,"path":2627,"stem":2628},"Маршрутизація, параметри запитів та APIRouter","\u002Fpython\u002Ffastapi\u002Ffastapi-routing-params","05.python\u002Ffastapi\u002F18.fastapi-routing-params",{"title":2630,"path":2631,"stem":2632},"Pydantic v2 у FastAPI — схеми, валідація та серіалізація","\u002Fpython\u002Ffastapi\u002Ffastapi-pydantic-schemas","05.python\u002Ffastapi\u002F19.fastapi-pydantic-schemas",{"title":2634,"path":2635,"stem":2636},"Dependency Injection — серце архітектури FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-dependency-injection","05.python\u002Ffastapi\u002F20.fastapi-dependency-injection",{"title":2638,"path":2639,"stem":2640},"Обробка помилок, Middleware та CORS у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-errors-middleware","05.python\u002Ffastapi\u002F21.fastapi-errors-middleware",{"title":2642,"path":2643,"stem":2644},"SQLAlchemy 2.0 — ORM, Core та Async Engine","\u002Fpython\u002Ffastapi\u002Fsqlalchemy-orm","05.python\u002Ffastapi\u002F22.sqlalchemy-orm",{"title":2646,"path":2647,"stem":2648},"Alembic — міграції бази даних","\u002Fpython\u002Ffastapi\u002Falembic-migrations","05.python\u002Ffastapi\u002F23.alembic-migrations",{"title":2650,"path":2651,"stem":2652},"Repository Pattern та Clean Architecture у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-repository-clean-arch","05.python\u002Ffastapi\u002F24.fastapi-repository-clean-arch",{"title":2654,"path":2655,"stem":2656},"Автентифікація та авторизація — JWT, OAuth2, RBAC","\u002Fpython\u002Ffastapi\u002Ffastapi-auth-security","05.python\u002Ffastapi\u002F25.fastapi-auth-security",{"title":2658,"path":2659,"stem":2660},"Тестування FastAPI — pytest, httpx, fixtures","\u002Fpython\u002Ffastapi\u002Ffastapi-testing","05.python\u002Ffastapi\u002F26.fastapi-testing",{"title":2662,"path":2663,"stem":2664},"Async на повну — Background Tasks, WebSockets, SSE та Celery","\u002Fpython\u002Ffastapi\u002Ffastapi-async-advanced","05.python\u002Ffastapi\u002F27.fastapi-async-advanced",{"title":2666,"path":2667,"stem":2668},"Deployment — Docker, CI\u002FCD, Monitoring","\u002Fpython\u002Ffastapi\u002Ffastapi-deployment","05.python\u002Ffastapi\u002F28.fastapi-deployment",{"title":2670,"path":2671,"stem":2672},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2674,"icon":2675,"path":2676,"stem":2677,"children":2678,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2679,2709,2732,2769,2798,2816,2850,2862,2871],{"title":2680,"icon":2681,"path":2682,"stem":2683,"children":2684,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2685,2689,2693,2697,2701,2705],{"title":2686,"path":2687,"stem":2688},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2690,"path":2691,"stem":2692},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2694,"path":2695,"stem":2696},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2698,"path":2699,"stem":2700},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2702,"path":2703,"stem":2704},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2706,"path":2707,"stem":2708},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2710,"icon":2675,"path":2711,"stem":2712,"children":2713,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2714,2718,2724,2728],{"title":2715,"path":2716,"stem":2717},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2719,"path":2720,"stem":2721,"children":2722},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2723],{"title":2719,"path":2720,"stem":2721},{"title":2725,"path":2726,"stem":2727},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2729,"path":2730,"stem":2731},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2733,"icon":2675,"path":2734,"stem":2735,"children":2736,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2737,2741,2745,2749,2753,2757,2761,2765],{"title":2738,"path":2739,"stem":2740},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2742,"path":2743,"stem":2744},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2746,"path":2747,"stem":2748},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2750,"path":2751,"stem":2752},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2754,"path":2755,"stem":2756},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2758,"path":2759,"stem":2760},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2762,"path":2763,"stem":2764},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2766,"path":2767,"stem":2768},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2770,"icon":2675,"path":2771,"stem":2772,"children":2773,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2774,2778,2782,2786,2790,2794],{"title":2775,"path":2776,"stem":2777},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2779,"path":2780,"stem":2781},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2783,"path":2784,"stem":2785},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2787,"path":2788,"stem":2789},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2791,"path":2792,"stem":2793},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2795,"path":2796,"stem":2797},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2799,"icon":2800,"path":2801,"stem":2802,"children":2803,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2804,2808,2812],{"title":2805,"path":2806,"stem":2807},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2809,"path":2810,"stem":2811},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":2813,"path":2814,"stem":2815},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":2817,"icon":2818,"path":2819,"stem":2820,"children":2821,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[2822,2826,2830,2834,2838,2842,2846],{"title":2823,"path":2824,"stem":2825},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":2827,"path":2828,"stem":2829},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":2831,"path":2832,"stem":2833},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":2835,"path":2836,"stem":2837},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":2839,"path":2840,"stem":2841},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":2843,"path":2844,"stem":2845},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":2847,"path":2848,"stem":2849},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":2847,"icon":793,"path":2851,"stem":2852,"children":2853,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[2854,2858],{"title":2855,"path":2856,"stem":2857},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":2859,"path":2860,"stem":2861},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":2863,"icon":2864,"path":2865,"stem":2866,"children":2867,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[2868],{"title":2863,"path":2869,"stem":2870},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":2872,"icon":2873,"path":2874,"stem":2875,"children":2876,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[2877],{"title":2872,"path":2878,"stem":2879},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":2881,"icon":2882,"path":2883,"stem":2884,"children":2885,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[2886,2962],{"title":2887,"icon":2888,"path":2889,"stem":2890,"children":2891},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[2892,2894,2898,2902,2906,2910,2914,2918,2922,2926,2930,2934,2938,2942,2946,2950,2954,2958],{"title":2893,"path":2889,"stem":2890},"Docker: від нуля до production",{"title":2895,"path":2896,"stem":2897},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":2899,"path":2900,"stem":2901},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":2903,"path":2904,"stem":2905},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":2907,"path":2908,"stem":2909},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":2911,"path":2912,"stem":2913},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":2915,"path":2916,"stem":2917},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":2919,"path":2920,"stem":2921},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":2923,"path":2924,"stem":2925},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":2927,"path":2928,"stem":2929},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":2931,"path":2932,"stem":2933},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":2935,"path":2936,"stem":2937},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":2939,"path":2940,"stem":2941},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":2943,"path":2944,"stem":2945},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":2947,"path":2948,"stem":2949},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":2951,"path":2952,"stem":2953},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":2955,"path":2956,"stem":2957},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":2959,"path":2960,"stem":2961},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":2963,"icon":2964,"path":2965,"stem":2966,"children":2967},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[2968,2970,2974,2978,2982,2986,2990,2994,2998],{"title":2969,"path":2965,"stem":2966},"Kubernetes: від розробки до production",{"title":2971,"path":2972,"stem":2973},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":2975,"path":2976,"stem":2977},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":2979,"path":2980,"stem":2981},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":2983,"path":2984,"stem":2985},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":2987,"path":2988,"stem":2989},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":2991,"path":2992,"stem":2993},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":2995,"path":2996,"stem":2997},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":2999,"path":3000,"stem":3001},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":3003,"icon":3004,"path":3005,"stem":3006,"children":3007,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[3008,3012,3016,3020,3024,3028,3032,3036,3040,3044,3048],{"title":3009,"path":3010,"stem":3011},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":3013,"path":3014,"stem":3015},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":3017,"path":3018,"stem":3019},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":3021,"path":3022,"stem":3023},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":3025,"path":3026,"stem":3027},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":3029,"path":3030,"stem":3031},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":3033,"path":3034,"stem":3035},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":3037,"path":3038,"stem":3039},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":3041,"path":3042,"stem":3043},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":3045,"path":3046,"stem":3047},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":3049,"path":3050,"stem":3051},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":3053,"icon":943,"path":3054,"stem":3055,"children":3056,"page":59},"DDD","\u002Fddd","10.ddd",[3057,3061,3065,3069,3073,3077,3081,3085,3089,3093,3097,3101,3105],{"title":3058,"path":3059,"stem":3060},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":3062,"path":3063,"stem":3064},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3066,"path":3067,"stem":3068},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3070,"path":3071,"stem":3072},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3074,"path":3075,"stem":3076},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3078,"path":3079,"stem":3080},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3082,"path":3083,"stem":3084},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3086,"path":3087,"stem":3088},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3090,"path":3091,"stem":3092},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3094,"path":3095,"stem":3096},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3098,"path":3099,"stem":3100},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3102,"path":3103,"stem":3104},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3106,"path":3107,"stem":3108},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3110,"icon":3111,"path":3112,"stem":3113,"children":3114,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3115,3119,3123,3127,3131,3135,3139],{"title":3116,"path":3117,"stem":3118},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3120,"path":3121,"stem":3122},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3124,"path":3125,"stem":3126},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3128,"path":3129,"stem":3130},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3132,"path":3133,"stem":3134},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3136,"path":3137,"stem":3138},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3140,"path":3141,"stem":3142},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3144,"icon":3145,"path":3146,"stem":3147,"children":3148,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3149,3153,3157,3161,3165,3169,3173,3177,3181,3185,3189,3193,3197,3201,3205,3209,3213,3217,3221,3225,3229,3233,3237,3241,3245,3249,3253,3257,3261,3265],{"title":3150,"path":3151,"stem":3152},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3154,"path":3155,"stem":3156},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3158,"path":3159,"stem":3160},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3162,"path":3163,"stem":3164},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3166,"path":3167,"stem":3168},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3170,"path":3171,"stem":3172},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3174,"path":3175,"stem":3176},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3178,"path":3179,"stem":3180},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3182,"path":3183,"stem":3184},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3186,"path":3187,"stem":3188},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3190,"path":3191,"stem":3192},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3194,"path":3195,"stem":3196},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3198,"path":3199,"stem":3200},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3202,"path":3203,"stem":3204},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3206,"path":3207,"stem":3208},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3210,"path":3211,"stem":3212},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3214,"path":3215,"stem":3216},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3218,"path":3219,"stem":3220},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3222,"path":3223,"stem":3224},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3226,"path":3227,"stem":3228},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3230,"path":3231,"stem":3232},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3234,"path":3235,"stem":3236},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3238,"path":3239,"stem":3240},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3242,"path":3243,"stem":3244},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3246,"path":3247,"stem":3248},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3250,"path":3251,"stem":3252},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3254,"path":3255,"stem":3256},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3258,"path":3259,"stem":3260},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3262,"path":3263,"stem":3264},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3266,"path":3267,"stem":3268},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3270,"path":3271,"stem":3272,"children":3273,"page":59},"AWS","\u002Faws","13.aws",[3274,3278,3282,3286,3290,3294,3298,3302,3306,3310,3314,3318,3322,3326,3330,3334,3338,3342],{"title":3275,"path":3276,"stem":3277},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3279,"path":3280,"stem":3281},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3283,"path":3284,"stem":3285},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3287,"path":3288,"stem":3289},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3291,"path":3292,"stem":3293},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3295,"path":3296,"stem":3297},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3299,"path":3300,"stem":3301},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3303,"path":3304,"stem":3305},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3307,"path":3308,"stem":3309},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3311,"path":3312,"stem":3313},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3315,"path":3316,"stem":3317},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3319,"path":3320,"stem":3321},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3323,"path":3324,"stem":3325},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3327,"path":3328,"stem":3329},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3331,"path":3332,"stem":3333},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3335,"path":3336,"stem":3337},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3339,"path":3340,"stem":3341},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3343,"path":3344,"stem":3345},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3347,"path":3348,"stem":3349,"children":3350,"page":59},"Ai Development","\u002Fai-development","14.ai-development",[3351],{"title":3352,"path":3353,"stem":3354,"children":3355,"page":59},"Foundations","\u002Fai-development\u002Ffoundations","14.ai-development\u002F00.foundations",[3356],{"title":3357,"path":3358,"stem":3359},"Модуль 0.1. Що таке Large Language Model (LLM)","\u002Fai-development\u002Ffoundations\u002Fwhat-is-llm","14.ai-development\u002F00.foundations\u002F01.what-is-llm",{"title":3361,"path":3362,"stem":3363,"children":3364,"page":59},"React Native","\u002Freact-native","15.react-native",[3365,3386],{"title":3366,"path":3367,"stem":3368,"children":3369,"page":59},"Version1","\u002Freact-native\u002Fversion1","15.react-native\u002Fversion1",[3370,3374,3378,3382],{"title":3371,"path":3372,"stem":3373},"Що таке React Native","\u002Freact-native\u002Fversion1\u002Fwhat-is-react-native","15.react-native\u002Fversion1\u002F01.what-is-react-native",{"title":3375,"path":3376,"stem":3377},"Як влаштований React Native «під капотом»","\u002Freact-native\u002Fversion1\u002Freact-native-architecture","15.react-native\u002Fversion1\u002F02.react-native-architecture",{"title":3379,"path":3380,"stem":3381},"Від React до React Native: ключові відмінності","\u002Freact-native\u002Fversion1\u002Freact-native-vs-react","15.react-native\u002Fversion1\u002F03.react-native-vs-react",{"title":3383,"path":3384,"stem":3385},"View та Text — фундаментальні будівельні блоки","\u002Freact-native\u002Fversion1\u002Fview-and-text","15.react-native\u002Fversion1\u002F04.view-and-text",{"title":3387,"path":3388,"stem":3389,"children":3390,"page":59},"Version2","\u002Freact-native\u002Fversion2","15.react-native\u002Fversion2",[3391,3395,3399,3403,3407,3411,3415,3419,3423,3427,3431,3435,3439,3443,3447,3451,3455,3459,3463,3467,3471,3475,3479,3483,3487,3491],{"title":3392,"path":3393,"stem":3394},"React Native — навіщо він потрібен","\u002Freact-native\u002Fversion2\u002Fwhy-react-native","15.react-native\u002Fversion2\u002F01.why-react-native",{"title":3396,"path":3397,"stem":3398},"Налаштування середовища розробки","\u002Freact-native\u002Fversion2\u002Fenvironment-setup","15.react-native\u002Fversion2\u002F02.environment-setup",{"title":3400,"path":3401,"stem":3402},"Expo і класичний React Native — два шляхи одного фреймворку","\u002Freact-native\u002Fversion2\u002Fexpo-vs-cli-landscape","15.react-native\u002Fversion2\u002F03.expo-vs-cli-landscape",{"title":3404,"path":3405,"stem":3406},"Середовище Expo — перший запуск","\u002Freact-native\u002Fversion2\u002Fexpo-setup-and-tooling","15.react-native\u002Fversion2\u002F04.expo-setup-and-tooling",{"title":3408,"path":3409,"stem":3410},"Структура проєкту та перші UI-примітиви","\u002Freact-native\u002Fversion2\u002Fproject-structure-and-conventions","15.react-native\u002Fversion2\u002F05.project-structure-and-conventions",{"title":3412,"path":3413,"stem":3414},"Базові компоненти React Native","\u002Freact-native\u002Fversion2\u002Fcore-components","15.react-native\u002Fversion2\u002F06.core-components",{"title":3416,"path":3417,"stem":3418},"Flexbox і layout у React Native","\u002Freact-native\u002Fversion2\u002Fflexbox-and-layout","15.react-native\u002Fversion2\u002F07.flexbox-and-layout",{"title":3420,"path":3421,"stem":3422},"StyleSheet і теми (light \u002F dark)","\u002Freact-native\u002Fversion2\u002Fstylesheet-and-theming","15.react-native\u002Fversion2\u002F08.stylesheet-and-theming",{"title":3424,"path":3425,"stem":3426},"Списки та віртуалізація","\u002Freact-native\u002Fversion2\u002Flists-and-virtualization","15.react-native\u002Fversion2\u002F09.lists-and-virtualization",{"title":3428,"path":3429,"stem":3430},"Форми, ввід і валідація","\u002Freact-native\u002Fversion2\u002Fforms-input-validation","15.react-native\u002Fversion2\u002F10.forms-input-validation",{"title":3432,"path":3433,"stem":3434},"Основи Expo Router","\u002Freact-native\u002Fversion2\u002Fexpo-router-basics","15.react-native\u002Fversion2\u002F11.expo-router-basics",{"title":3436,"path":3437,"stem":3438},"Вкладені навігатори та модалки","\u002Freact-native\u002Fversion2\u002Fnested-navigators-and-modals","15.react-native\u002Fversion2\u002F12.nested-navigators-and-modals",{"title":3440,"path":3441,"stem":3442},"Deep linking і параметри маршрутів","\u002Freact-native\u002Fversion2\u002Fdeep-linking-and-params","15.react-native\u002Fversion2\u002F13.deep-linking-and-params",{"title":3444,"path":3445,"stem":3446},"Робота з мережею та життєвий цикл застосунку","\u002Freact-native\u002Fversion2\u002Fnetworking-and-app-lifecycle","15.react-native\u002Fversion2\u002F14.networking-and-app-lifecycle",{"title":3448,"path":3449,"stem":3450},"Redux Toolkit на мобільних платформах","\u002Freact-native\u002Fversion2\u002Fredux-toolkit-on-mobile","15.react-native\u002Fversion2\u002F15.redux-toolkit-on-mobile",{"title":3452,"path":3453,"stem":3454},"RTK Query на мобільних платформах","\u002Freact-native\u002Fversion2\u002Frtk-query-mobile","15.react-native\u002Fversion2\u002F16.rtk-query-mobile",{"title":3456,"path":3457,"stem":3458},"Автентифікація та Безпечне Зберігання","\u002Freact-native\u002Fversion2\u002Fauth-secure-storage","15.react-native\u002Fversion2\u002F18.auth-secure-storage",{"title":3460,"path":3461,"stem":3462},"Локальне сховище — AsyncStorage, MMKV, SQLite","\u002Freact-native\u002Fversion2\u002Flocal-storage-mmkv-sqlite","15.react-native\u002Fversion2\u002F19.local-storage-mmkv-sqlite",{"title":3464,"path":3465,"stem":3466},"Офлайн-First і синхронізація","\u002Freact-native\u002Fversion2\u002Foffline-first-sync","15.react-native\u002Fversion2\u002F20.offline-first-sync",{"title":3468,"path":3469,"stem":3470},"Камера, медіа та файлова система","\u002Freact-native\u002Fversion2\u002Fcamera-media-filesystem","15.react-native\u002Fversion2\u002F21.camera-media-filesystem",{"title":3472,"path":3473,"stem":3474},"Карти та геолокація","\u002Freact-native\u002Fversion2\u002Fmaps-and-location","15.react-native\u002Fversion2\u002F22.maps-and-location",{"title":3476,"path":3477,"stem":3478},"Жести та дотики","\u002Freact-native\u002Fversion2\u002Fgestures-and-touch","15.react-native\u002Fversion2\u002F23.gestures-and-touch",{"title":3480,"path":3481,"stem":3482},"Анімації з Reanimated","\u002Freact-native\u002Fversion2\u002Freanimated-animations","15.react-native\u002Fversion2\u002F24.reanimated-animations",{"title":3484,"path":3485,"stem":3486},"Push і локальні сповіщення","\u002Freact-native\u002Fversion2\u002Fpush-and-local-notifications","15.react-native\u002Fversion2\u002F25.push-and-local-notifications",{"title":3488,"path":3489,"stem":3490},"Доступність та інтернаціоналізація","\u002Freact-native\u002Fversion2\u002Faccessibility-and-i18n","15.react-native\u002Fversion2\u002F26.accessibility-and-i18n",{"title":3492,"path":3493,"stem":3494},"EAS Build та профілі збірки","\u002Freact-native\u002Fversion2\u002Feas-build-and-profiles","15.react-native\u002Fversion2\u002F29.eas-build-and-profiles",{"title":3496,"path":3497,"stem":3498,"children":3499,"page":59},"Ai Python","\u002Fai-python","16.ai-python",[3500,3504,3508],{"title":3501,"path":3502,"stem":3503},"Вступ до штучного інтелекту та машинного навчання","\u002Fai-python\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai",{"title":3505,"path":3506,"stem":3507},"Знайомство з Jupyter Notebook та JupyterLab","\u002Fai-python\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook",{"title":3509,"path":3510,"stem":3511},"Робота з даними з використанням NumPy і pandas","\u002Fai-python\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas",{"title":3513,"icon":658,"path":3514,"stem":3515,"children":3516,"page":59},"Клієнт-серверна архітектура","\u002Fclient-server-architecture","17.client-server-architecture",[3517,3521],{"title":3518,"path":3519,"stem":3520},"Архітектура клієнт-серверних систем та основи Go","\u002Fclient-server-architecture\u002Fclient-server-architecture-and-go","17.client-server-architecture\u002F01.client-server-architecture-and-go",{"title":3522,"path":3523,"stem":3524},"Система типів та модель пам’яті мови Go","\u002Fclient-server-architecture\u002Ftype-system-and-memory-model","17.client-server-architecture\u002F02.type-system-and-memory-model",{"title":3526,"icon":1946,"path":3527,"stem":3528,"children":3529,"page":59},"Розробка WEB-застосувань","\u002Fweb-development","18.web-development",[3530,3575,3613,3642],{"title":3531,"icon":658,"path":3532,"stem":3533,"children":3534,"page":59},"Архітектура комп'ютерних мереж та мережеві протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols","18.web-development\u002F01.network-architecture-and-protocols",[3535,3539,3543,3547,3551,3555,3559,3563,3567,3571],{"title":3536,"path":3537,"stem":3538},"Еволюція веброзробки та модель клієнт-сервер","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fweb-evolution-client-server","18.web-development\u002F01.network-architecture-and-protocols\u002F01.web-evolution-client-server",{"title":3540,"path":3541,"stem":3542},"Еталонна модель OSI","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fosi-model","18.web-development\u002F01.network-architecture-and-protocols\u002F02.osi-model",{"title":3544,"path":3545,"stem":3546},"Стек протоколів TCP\u002FIP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-ip-stack","18.web-development\u002F01.network-architecture-and-protocols\u002F03.tcp-ip-stack",{"title":3548,"path":3549,"stem":3550},"IP-адресація, порти та сокети","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fip-addressing-ports-sockets","18.web-development\u002F01.network-architecture-and-protocols\u002F04.ip-addressing-ports-sockets",{"title":3552,"path":3553,"stem":3554},"Протоколи TCP та UDP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-udp-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F05.tcp-udp-protocols",{"title":3556,"path":3557,"stem":3558},"Система доменних імен DNS","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fdns-system","18.web-development\u002F01.network-architecture-and-protocols\u002F06.dns-system",{"title":3560,"path":3561,"stem":3562},"Протокол SMTP та поштові протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fsmtp-email-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F07.smtp-email-protocols",{"title":3564,"path":3565,"stem":3566},"Протокол WebSocket","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fwebsocket-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F08.websocket-protocol",{"title":3568,"path":3569,"stem":3570},"Протокол SSH","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fssh-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F09.ssh-protocol",{"title":3572,"path":3573,"stem":3574},"Огляд сучасних серверних технологій","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fmodern-backend-technologies","18.web-development\u002F01.network-architecture-and-protocols\u002F10.modern-backend-technologies",{"title":3576,"icon":3577,"path":3578,"stem":3579,"children":3580,"page":59},"Протокол HTTP та захищена передача даних HTTPS","i-lucide-lock","\u002Fweb-development\u002Fhttp-and-https","18.web-development\u002F02.http-and-https",[3581,3585,3589,3593,3597,3601,3605,3609],{"title":3582,"path":3583,"stem":3584},"Вступ до протоколу HTTP та еволюція веб-технологій","\u002Fweb-development\u002Fhttp-and-https\u002Fintroduction-and-evolution","18.web-development\u002F02.http-and-https\u002F01.introduction-and-evolution",{"title":3586,"path":3587,"stem":3588},"Анатомія HTTP-запиту","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-request-structure","18.web-development\u002F02.http-and-https\u002F02.http-request-structure",{"title":3590,"path":3591,"stem":3592},"Анатомія HTTP-відповіді","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-response-structure","18.web-development\u002F02.http-and-https\u002F03.http-response-structure",{"title":3594,"path":3595,"stem":3596},"Методи HTTP та їхня семантика","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-methods","18.web-development\u002F02.http-and-https\u002F04.http-methods",{"title":3598,"path":3599,"stem":3600},"Коди статусу HTTP та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-status-codes","18.web-development\u002F02.http-and-https\u002F05.http-status-codes",{"title":3602,"path":3603,"stem":3604},"HTTP-заголовки та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-headers","18.web-development\u002F02.http-and-https\u002F06.http-headers",{"title":3606,"path":3607,"stem":3608},"CORS та механізми безпеки HTTP","\u002Fweb-development\u002Fhttp-and-https\u002Fcors-and-security","18.web-development\u002F02.http-and-https\u002F07.cors-and-security",{"title":3610,"path":3611,"stem":3612},"HTTPS та криптографічні основи TLS","\u002Fweb-development\u002Fhttp-and-https\u002Fhttps-and-tls","18.web-development\u002F02.http-and-https\u002F08.https-and-tls",{"title":3614,"icon":2326,"path":3615,"stem":3616,"children":3617,"page":59},"Система типів мови TypeScript","\u002Fweb-development\u002Ftypescript-type-system","18.web-development\u002F03.typescript-type-system",[3618,3622,3626,3630,3634,3638],{"title":3619,"path":3620,"stem":3621},"Знайомство з TypeScript Compiler","\u002Fweb-development\u002Ftypescript-type-system\u002Fintroduction-compiler-config","18.web-development\u002F03.typescript-type-system\u002F01.introduction-compiler-config",{"title":3623,"path":3624,"stem":3625},"Примітивні типи даних: string, number, boolean","\u002Fweb-development\u002Ftypescript-type-system\u002Fprimitive-special-types","18.web-development\u002F03.typescript-type-system\u002F02.primitive-special-types",{"title":3627,"path":3628,"stem":3629},"Масиви, кортежі та об","\u002Fweb-development\u002Ftypescript-type-system\u002Farrays-tuples-objects","18.web-development\u002F03.typescript-type-system\u002F03.arrays-tuples-objects",{"title":3631,"path":3632,"stem":3633},"Union типи, Intersection типи та літеральні типи","\u002Fweb-development\u002Ftypescript-type-system\u002Funion-intersection-literals","18.web-development\u002F03.typescript-type-system\u002F04.union-intersection-literals",{"title":3635,"path":3636,"stem":3637},"Type Narrowing (звуження типів)","\u002Fweb-development\u002Ftypescript-type-system\u002Ftype-narrowing","18.web-development\u002F03.typescript-type-system\u002F05.type-narrowing",{"title":3639,"path":3640,"stem":3641},"Типізація функцій","\u002Fweb-development\u002Ftypescript-type-system\u002Ffunctions-typing","18.web-development\u002F03.typescript-type-system\u002F06.functions-typing",{"title":3643,"icon":2326,"path":3644,"stem":3645,"children":3646,"page":59},"Розширені засоби мови TypeScript","\u002Fweb-development\u002Ftypescript-advanced","18.web-development\u002F04.typescript-advanced",[3647,3651,3655,3659,3663,3667],{"title":3648,"path":3649,"stem":3650},"Interfaces та Classes","\u002Fweb-development\u002Ftypescript-advanced\u002Finterfaces-classes","18.web-development\u002F04.typescript-advanced\u002F01.interfaces-classes",{"title":3652,"path":3653,"stem":3654},"Основи Generic типів","\u002Fweb-development\u002Ftypescript-advanced\u002Fgenerics-fundamentals","18.web-development\u002F04.typescript-advanced\u002F02.generics-fundamentals",{"title":3656,"path":3657,"stem":3658},"Enums та Decorators","\u002Fweb-development\u002Ftypescript-advanced\u002Fenums-decorators","18.web-development\u002F04.typescript-advanced\u002F03.enums-decorators",{"title":3660,"path":3661,"stem":3662},"Utility Types","\u002Fweb-development\u002Ftypescript-advanced\u002Futility-types","18.web-development\u002F04.typescript-advanced\u002F04.utility-types",{"title":3664,"path":3665,"stem":3666},"Mapped та Conditional Types","\u002Fweb-development\u002Ftypescript-advanced\u002Fmapped-conditional-types","18.web-development\u002F04.typescript-advanced\u002F05.mapped-conditional-types",{"title":3668,"path":3669,"stem":3670},"Модулі та Strict Mode","\u002Fweb-development\u002Ftypescript-advanced\u002Fmodules-strict-mode","18.web-development\u002F04.typescript-advanced\u002F06.modules-strict-mode",{"title":3672,"path":3673,"stem":3674,"children":3675,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[3676,3680,3684,3688,3692,3696,3700,3704,3708,3712,3716,3720],{"title":3677,"path":3678,"stem":3679},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":3681,"path":3682,"stem":3683},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":3685,"path":3686,"stem":3687},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":3689,"path":3690,"stem":3691},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":3693,"path":3694,"stem":3695},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":3697,"path":3698,"stem":3699},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":3701,"path":3702,"stem":3703},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":3705,"path":3706,"stem":3707},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":3709,"path":3710,"stem":3711},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":3713,"path":3714,"stem":3715},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":3717,"path":3718,"stem":3719},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":3721,"path":3722,"stem":3723},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":3725,"path":3726,"stem":3727},"Тестування компонентів діаграм","\u002Ftest-components","98.test-components",{"id":3729,"title":3448,"body":3730,"description":34456,"extension":34457,"links":34458,"meta":34459,"navigation":3964,"path":3449,"seo":34460,"stem":3450,"__hash__":34461},"docs\u002F15.react-native\u002Fversion2\u002F15.redux-toolkit-on-mobile.md",{"type":3731,"value":3732,"toc":34366},"minimark",[3733,3737,3742,3746,3751,3754,3826,3832,3874,3898,3902,3905,3913,3916,3920,3923,4087,4095,4113,4117,4122,4473,4491,4494,4497,4501,4504,4515,4560,4574,4576,4580,4584,4587,4616,4623,4661,4671,4677,4679,4683,4686,4690,4700,4912,4917,4939,4943,4952,5035,5040,5074,5109,5113,5130,5270,5275,5298,5409,5413,5416,5554,5559,5609,5611,5615,5618,5621,5628,6314,6328,6332,6339,6835,6840,6872,6913,6915,6919,6922,6926,6934,7018,7024,7032,7041,7321,7328,7334,7412,7414,7418,7423,7427,7431,7437,7468,7471,7475,7478,7760,7780,7978,8077,8353,8355,8362,8368,8399,8435,8439,9413,9417,9422,9432,9500,9570,9574,9579,9845,9890,9894,9904,9987,10115,10388,10431,10435,10843,11467,11473,11482,11851,11858,11875,11927,11934,11941,12393,12488,12496,12515,13259,13446,13450,13453,13757,14045,14049,14055,14441,14448,14450,14452,14459,14470,14472,14476,14482,14486,14823,14827,14908,14912,15305,15309,15981,15985,16125,16129,16358,16362,16879,16881,16887,16891,16894,17003,17008,17308,17606,17608,17615,17625,17633,18023,18026,18090,18092,18099,18108,18112,18115,18238,18244,18253,18574,18578,18591,18680,18685,18896,18898,18906,18917,19033,19040,19046,19244,19246,19253,19269,19846,19848,19855,19873,19877,19887,19892,20002,20007,20012,20037,20166,20170,20177,20401,20405,20490,20495,20977,20981,20990,21530,21820,21824,21827,21831,22436,22462,22466,22900,22904,23529,23533,23870,23874,24150,24747,25360,25366,26000,26004,26167,26169,26173,26177,26180,26186,26205,26209,26659,26663,26857,26861,27297,27299,27303,27309,27438,27442,27576,27597,27599,27603,27613,28304,28306,28310,28321,28325,28402,28406,28436,28440,28443,28779,28781,28785,28788,29112,29114,29118,29242,29244,29248,29251,29270,29274,29319,29323,32548,32550,32554,32557,32561,32788,32794,33384,33388,33639,33646,34169,34171,34175,34211,34213,34217,34302,34304,34308,34362],[3734,3735,3448],"h1",{"id":3736},"redux-toolkit-на-мобільних-платформах",[3738,3739,3741],"h2",{"id":3740},"встановлення-та-налаштування-у-react-native-проєкті","Встановлення та налаштування у React Native проєкті",[3743,3744,3745],"p",{},"Перед тим як заглибитися у концепції Redux Toolkit, давайте встановимо необхідні бібліотеки та створимо базову структуру проєкту.",[3747,3748,3750],"h3",{"id":3749},"крок-1-встановлення-залежностей","Крок 1: Встановлення залежностей",[3743,3752,3753],{},"Redux Toolkit та React-Redux є окремими npm-пакетами, які потрібно додати до вашого проєкту:",[3755,3756,3757,3789,3808],"tabs",{},[3758,3759,3761],"tabs-item",{"label":3760},"npm",[3762,3763,3768],"pre",{"className":3764,"code":3765,"language":3766,"meta":3767,"style":3767},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","npm install @reduxjs\u002Ftoolkit react-redux\n","bash","",[3769,3770,3771],"code",{"__ignoreMap":3767},[3772,3773,3776,3779,3783,3786],"span",{"class":3774,"line":3775},"line",1,[3772,3777,3760],{"class":3778},"s8Opu",[3772,3780,3782],{"class":3781},"sbdoH"," install",[3772,3784,3785],{"class":3781}," @reduxjs\u002Ftoolkit",[3772,3787,3788],{"class":3781}," react-redux\n",[3758,3790,3792],{"label":3791},"yarn",[3762,3793,3795],{"className":3764,"code":3794,"language":3766,"meta":3767,"style":3767},"yarn add @reduxjs\u002Ftoolkit react-redux\n",[3769,3796,3797],{"__ignoreMap":3767},[3772,3798,3799,3801,3804,3806],{"class":3774,"line":3775},[3772,3800,3791],{"class":3778},[3772,3802,3803],{"class":3781}," add",[3772,3805,3785],{"class":3781},[3772,3807,3788],{"class":3781},[3758,3809,3811],{"label":3810},"pnpm",[3762,3812,3814],{"className":3764,"code":3813,"language":3766,"meta":3767,"style":3767},"pnpm add @reduxjs\u002Ftoolkit react-redux\n",[3769,3815,3816],{"__ignoreMap":3767},[3772,3817,3818,3820,3822,3824],{"class":3774,"line":3775},[3772,3819,3810],{"class":3778},[3772,3821,3803],{"class":3781},[3772,3823,3785],{"class":3781},[3772,3825,3788],{"class":3781},[3743,3827,3828],{},[3829,3830,3831],"strong",{},"Що ми встановили:",[3833,3834,3835,3855],"ul",{},[3836,3837,3838,3843,3844,3847,3848,3847,3851,3854],"li",{},[3829,3839,3840],{},[3769,3841,3842],{},"@reduxjs\u002Ftoolkit"," — офіційний набір інструментів Redux, який включає ",[3769,3845,3846],{},"createSlice",", ",[3769,3849,3850],{},"configureStore",[3769,3852,3853],{},"createAsyncThunk"," та інші утиліти",[3836,3856,3857,3862,3863,3847,3866,3869,3870,3873],{},[3829,3858,3859],{},[3769,3860,3861],{},"react-redux"," — офіційні React-біндінги для Redux, які надають ",[3769,3864,3865],{},"Provider",[3769,3867,3868],{},"useSelector"," та ",[3769,3871,3872],{},"useDispatch"," хуки",[3875,3876,3877,3883,3895],"note",{},[3743,3878,3879,3882],{},[3829,3880,3881],{},"Версії:"," Переконайтеся, що використовуєте актуальні версії:",[3833,3884,3885,3890],{},[3836,3886,3887,3889],{},[3769,3888,3842],{},": ^2.0.0 або новіша",[3836,3891,3892,3894],{},[3769,3893,3861],{},": ^9.0.0 або новіша",[3743,3896,3897],{},"Ці версії повністю сумісні з React Native та підтримують TypeScript з коробки.",[3747,3899,3901],{"id":3900},"крок-2-створення-структури-директорій","Крок 2: Створення структури директорій",[3743,3903,3904],{},"Створіть наступну файлову структуру у вашому проєкті:",[3762,3906,3911],{"className":3907,"code":3909,"language":3910},[3908],"language-text","src\u002F\n├── store\u002F\n│   ├── index.ts           # Налаштування Store\n│   ├── hooks.ts           # Типізовані хуки\n│   ├── slices\u002F            # Модулі стану (Slices)\n│   │   ├── tripsSlice.ts\n│   │   └── settingsSlice.ts\n│   └── thunks\u002F            # Асинхронні дії\n│       └── tripsThunks.ts\n","text",[3769,3912,3909],{"__ignoreMap":3767},[3743,3914,3915],{},"Ця структура допоможе організувати код та полегшить масштабування застосунку.",[3747,3917,3919],{"id":3918},"крок-3-базова-конфігурація-store","Крок 3: Базова конфігурація Store",[3743,3921,3922],{},"Створимо мінімальний робочий Store, який ви зможете розширювати:",[3762,3924,3928],{"className":3925,"code":3926,"language":3927,"meta":3767,"style":3767},"language-typescript shiki shiki-themes light-plus dark-plus dark-plus","\u002F\u002F src\u002Fstore\u002Findex.ts\nimport { configureStore } from '@reduxjs\u002Ftoolkit'\n\n\u002F\u002F Поки що створюємо порожній Store\nexport const store = configureStore({\n    reducer: {\n        \u002F\u002F Тут будуть підключатися наші slices\n    },\n})\n\n\u002F\u002F Експортуємо типи для TypeScript\nexport type RootState = ReturnType\u003Ctypeof store.getState>\nexport type AppDispatch = typeof store.dispatch\n","typescript",[3769,3929,3930,3936,3959,3966,3972,3994,4003,4009,4015,4021,4026,4032,4066],{"__ignoreMap":3767},[3772,3931,3932],{"class":3774,"line":3775},[3772,3933,3935],{"class":3934},"spJ8K","\u002F\u002F src\u002Fstore\u002Findex.ts\n",[3772,3937,3939,3943,3947,3950,3953,3956],{"class":3774,"line":3938},2,[3772,3940,3942],{"class":3941},"s8xlr","import",[3772,3944,3946],{"class":3945},"sHH4Y"," { ",[3772,3948,3850],{"class":3949},"siwwj",[3772,3951,3952],{"class":3945}," } ",[3772,3954,3955],{"class":3941},"from",[3772,3957,3958],{"class":3781}," '@reduxjs\u002Ftoolkit'\n",[3772,3960,3962],{"class":3774,"line":3961},3,[3772,3963,3965],{"emptyLinePlaceholder":3964},true,"\n",[3772,3967,3969],{"class":3774,"line":3968},4,[3772,3970,3971],{"class":3934},"\u002F\u002F Поки що створюємо порожній Store\n",[3772,3973,3975,3978,3982,3986,3989,3991],{"class":3774,"line":3974},5,[3772,3976,3977],{"class":3941},"export",[3772,3979,3981],{"class":3980},"su1O8"," const",[3772,3983,3985],{"class":3984},"s-QsJ"," store",[3772,3987,3988],{"class":3945}," = ",[3772,3990,3850],{"class":3778},[3772,3992,3993],{"class":3945},"({\n",[3772,3995,3997,4000],{"class":3774,"line":3996},6,[3772,3998,3999],{"class":3949},"    reducer:",[3772,4001,4002],{"class":3945}," {\n",[3772,4004,4006],{"class":3774,"line":4005},7,[3772,4007,4008],{"class":3934},"        \u002F\u002F Тут будуть підключатися наші slices\n",[3772,4010,4012],{"class":3774,"line":4011},8,[3772,4013,4014],{"class":3945},"    },\n",[3772,4016,4018],{"class":3774,"line":4017},9,[3772,4019,4020],{"class":3945},"})\n",[3772,4022,4024],{"class":3774,"line":4023},10,[3772,4025,3965],{"emptyLinePlaceholder":3964},[3772,4027,4029],{"class":3774,"line":4028},11,[3772,4030,4031],{"class":3934},"\u002F\u002F Експортуємо типи для TypeScript\n",[3772,4033,4035,4037,4040,4044,4046,4049,4052,4055,4057,4060,4063],{"class":3774,"line":4034},12,[3772,4036,3977],{"class":3941},[3772,4038,4039],{"class":3980}," type",[3772,4041,4043],{"class":4042},"sN1BT"," RootState",[3772,4045,3988],{"class":3945},[3772,4047,4048],{"class":4042},"ReturnType",[3772,4050,4051],{"class":3945},"\u003C",[3772,4053,4054],{"class":3980},"typeof",[3772,4056,3985],{"class":3949},[3772,4058,4059],{"class":3945},".",[3772,4061,4062],{"class":3949},"getState",[3772,4064,4065],{"class":3945},">\n",[3772,4067,4069,4071,4073,4076,4078,4080,4082,4084],{"class":3774,"line":4068},13,[3772,4070,3977],{"class":3941},[3772,4072,4039],{"class":3980},[3772,4074,4075],{"class":4042}," AppDispatch",[3772,4077,3988],{"class":3945},[3772,4079,4054],{"class":3980},[3772,4081,3985],{"class":3949},[3772,4083,4059],{"class":3945},[3772,4085,4086],{"class":3949},"dispatch\n",[3743,4088,4089],{},[3829,4090,4091,4092,4094],{},"Що робить ",[3769,4093,3850],{},":",[3833,4096,4097,4100,4107,4110],{},[3836,4098,4099],{},"Автоматично налаштовує Redux DevTools Extension (для дебагу)",[3836,4101,4102,4103,4106],{},"Додає ",[3769,4104,4105],{},"redux-thunk"," middleware (для асинхронних дій)",[3836,4108,4109],{},"Підключає перевірки на мутації та серіалізованість у режимі розробки",[3836,4111,4112],{},"Комбінує всі редюсери в єдине дерево стану",[3747,4114,4116],{"id":4115},"крок-4-підключення-provider-до-застосунку","Крок 4: Підключення Provider до застосунку",[3743,4118,4119,4120,4094],{},"Огорніть кореневий компонент вашого застосунку у ",[3769,4121,3865],{},[3755,4123,4124,4317],{},[3758,4125,4127],{"label":4126},"Expo Router",[3762,4128,4132],{"className":4129,"code":4130,"language":4131,"meta":3767,"style":3767},"language-tsx shiki shiki-themes light-plus dark-plus dark-plus","\u002F\u002F app\u002F_layout.tsx\nimport { Provider } from 'react-redux'\nimport { store } from '@\u002Fstore'\nimport { Stack } from 'expo-router'\n\nexport default function RootLayout() {\n    return (\n        \u003CProvider store={store}>\n            \u003CStack>\n                \u003CStack.Screen name=\"(tabs)\" options={{ headerShown: false }} \u002F>\n            \u003C\u002FStack>\n        \u003C\u002FProvider>\n    )\n}\n","tsx",[3769,4133,4134,4139,4154,4170,4186,4190,4206,4214,4238,4247,4288,4297,4306,4311],{"__ignoreMap":3767},[3772,4135,4136],{"class":3774,"line":3775},[3772,4137,4138],{"class":3934},"\u002F\u002F app\u002F_layout.tsx\n",[3772,4140,4141,4143,4145,4147,4149,4151],{"class":3774,"line":3938},[3772,4142,3942],{"class":3941},[3772,4144,3946],{"class":3945},[3772,4146,3865],{"class":3949},[3772,4148,3952],{"class":3945},[3772,4150,3955],{"class":3941},[3772,4152,4153],{"class":3781}," 'react-redux'\n",[3772,4155,4156,4158,4160,4163,4165,4167],{"class":3774,"line":3961},[3772,4157,3942],{"class":3941},[3772,4159,3946],{"class":3945},[3772,4161,4162],{"class":3949},"store",[3772,4164,3952],{"class":3945},[3772,4166,3955],{"class":3941},[3772,4168,4169],{"class":3781}," '@\u002Fstore'\n",[3772,4171,4172,4174,4176,4179,4181,4183],{"class":3774,"line":3968},[3772,4173,3942],{"class":3941},[3772,4175,3946],{"class":3945},[3772,4177,4178],{"class":3949},"Stack",[3772,4180,3952],{"class":3945},[3772,4182,3955],{"class":3941},[3772,4184,4185],{"class":3781}," 'expo-router'\n",[3772,4187,4188],{"class":3774,"line":3974},[3772,4189,3965],{"emptyLinePlaceholder":3964},[3772,4191,4192,4194,4197,4200,4203],{"class":3774,"line":3996},[3772,4193,3977],{"class":3941},[3772,4195,4196],{"class":3941}," default",[3772,4198,4199],{"class":3980}," function",[3772,4201,4202],{"class":3778}," RootLayout",[3772,4204,4205],{"class":3945},"() {\n",[3772,4207,4208,4211],{"class":3774,"line":4005},[3772,4209,4210],{"class":3941},"    return",[3772,4212,4213],{"class":3945}," (\n",[3772,4215,4216,4220,4222,4225,4228,4231,4233,4236],{"class":3774,"line":4011},[3772,4217,4219],{"class":4218},"s0P7L","        \u003C",[3772,4221,3865],{"class":4042},[3772,4223,3985],{"class":4224},"sa4r_",[3772,4226,4227],{"class":3945},"=",[3772,4229,4230],{"class":3980},"{",[3772,4232,4162],{"class":3949},[3772,4234,4235],{"class":3980},"}",[3772,4237,4065],{"class":4218},[3772,4239,4240,4243,4245],{"class":3774,"line":4017},[3772,4241,4242],{"class":4218},"            \u003C",[3772,4244,4178],{"class":4042},[3772,4246,4065],{"class":4218},[3772,4248,4249,4252,4255,4258,4260,4263,4266,4268,4270,4274,4277,4280,4283,4285],{"class":3774,"line":4023},[3772,4250,4251],{"class":4218},"                \u003C",[3772,4253,4254],{"class":4042},"Stack.Screen",[3772,4256,4257],{"class":4224}," name",[3772,4259,4227],{"class":3945},[3772,4261,4262],{"class":3781},"\"(tabs)\"",[3772,4264,4265],{"class":4224}," options",[3772,4267,4227],{"class":3945},[3772,4269,4230],{"class":3980},[3772,4271,4273],{"class":4272},"sD7JJ","{ ",[3772,4275,4276],{"class":3949},"headerShown:",[3772,4278,4279],{"class":3980}," false",[3772,4281,4282],{"class":4272}," }",[3772,4284,4235],{"class":3980},[3772,4286,4287],{"class":4218}," \u002F>\n",[3772,4289,4290,4293,4295],{"class":3774,"line":4028},[3772,4291,4292],{"class":4218},"            \u003C\u002F",[3772,4294,4178],{"class":4042},[3772,4296,4065],{"class":4218},[3772,4298,4299,4302,4304],{"class":3774,"line":4034},[3772,4300,4301],{"class":4218},"        \u003C\u002F",[3772,4303,3865],{"class":4042},[3772,4305,4065],{"class":4218},[3772,4307,4308],{"class":3774,"line":4068},[3772,4309,4310],{"class":3945},"    )\n",[3772,4312,4314],{"class":3774,"line":4313},14,[3772,4315,4316],{"class":3945},"}\n",[3758,4318,4320],{"label":4319},"React Navigation",[3762,4321,4323],{"className":4129,"code":4322,"language":4131,"meta":3767,"style":3767},"\u002F\u002F App.tsx\nimport { Provider } from 'react-redux'\nimport { store } from '.\u002Fsrc\u002Fstore'\nimport { NavigationContainer } from '@react-navigation\u002Fnative'\nimport { RootNavigator } from '.\u002Fsrc\u002Fnavigation'\n\nexport default function App() {\n    return (\n        \u003CProvider store={store}>\n            \u003CNavigationContainer>\n                \u003CRootNavigator \u002F>\n            \u003C\u002FNavigationContainer>\n        \u003C\u002FProvider>\n    )\n}\n",[3769,4324,4325,4330,4344,4359,4375,4391,4395,4408,4414,4432,4440,4448,4456,4464,4468],{"__ignoreMap":3767},[3772,4326,4327],{"class":3774,"line":3775},[3772,4328,4329],{"class":3934},"\u002F\u002F App.tsx\n",[3772,4331,4332,4334,4336,4338,4340,4342],{"class":3774,"line":3938},[3772,4333,3942],{"class":3941},[3772,4335,3946],{"class":3945},[3772,4337,3865],{"class":3949},[3772,4339,3952],{"class":3945},[3772,4341,3955],{"class":3941},[3772,4343,4153],{"class":3781},[3772,4345,4346,4348,4350,4352,4354,4356],{"class":3774,"line":3961},[3772,4347,3942],{"class":3941},[3772,4349,3946],{"class":3945},[3772,4351,4162],{"class":3949},[3772,4353,3952],{"class":3945},[3772,4355,3955],{"class":3941},[3772,4357,4358],{"class":3781}," '.\u002Fsrc\u002Fstore'\n",[3772,4360,4361,4363,4365,4368,4370,4372],{"class":3774,"line":3968},[3772,4362,3942],{"class":3941},[3772,4364,3946],{"class":3945},[3772,4366,4367],{"class":3949},"NavigationContainer",[3772,4369,3952],{"class":3945},[3772,4371,3955],{"class":3941},[3772,4373,4374],{"class":3781}," '@react-navigation\u002Fnative'\n",[3772,4376,4377,4379,4381,4384,4386,4388],{"class":3774,"line":3974},[3772,4378,3942],{"class":3941},[3772,4380,3946],{"class":3945},[3772,4382,4383],{"class":3949},"RootNavigator",[3772,4385,3952],{"class":3945},[3772,4387,3955],{"class":3941},[3772,4389,4390],{"class":3781}," '.\u002Fsrc\u002Fnavigation'\n",[3772,4392,4393],{"class":3774,"line":3996},[3772,4394,3965],{"emptyLinePlaceholder":3964},[3772,4396,4397,4399,4401,4403,4406],{"class":3774,"line":4005},[3772,4398,3977],{"class":3941},[3772,4400,4196],{"class":3941},[3772,4402,4199],{"class":3980},[3772,4404,4405],{"class":3778}," App",[3772,4407,4205],{"class":3945},[3772,4409,4410,4412],{"class":3774,"line":4011},[3772,4411,4210],{"class":3941},[3772,4413,4213],{"class":3945},[3772,4415,4416,4418,4420,4422,4424,4426,4428,4430],{"class":3774,"line":4017},[3772,4417,4219],{"class":4218},[3772,4419,3865],{"class":4042},[3772,4421,3985],{"class":4224},[3772,4423,4227],{"class":3945},[3772,4425,4230],{"class":3980},[3772,4427,4162],{"class":3949},[3772,4429,4235],{"class":3980},[3772,4431,4065],{"class":4218},[3772,4433,4434,4436,4438],{"class":3774,"line":4023},[3772,4435,4242],{"class":4218},[3772,4437,4367],{"class":4042},[3772,4439,4065],{"class":4218},[3772,4441,4442,4444,4446],{"class":3774,"line":4028},[3772,4443,4251],{"class":4218},[3772,4445,4383],{"class":4042},[3772,4447,4287],{"class":4218},[3772,4449,4450,4452,4454],{"class":3774,"line":4034},[3772,4451,4292],{"class":4218},[3772,4453,4367],{"class":4042},[3772,4455,4065],{"class":4218},[3772,4457,4458,4460,4462],{"class":3774,"line":4068},[3772,4459,4301],{"class":4218},[3772,4461,3865],{"class":4042},[3772,4463,4065],{"class":4218},[3772,4465,4466],{"class":3774,"line":4313},[3772,4467,4310],{"class":3945},[3772,4469,4471],{"class":3774,"line":4470},15,[3772,4472,4316],{"class":3945},[4474,4475,4476,4479,4480,4482,4483,4486,4487,3869,4489,4059],"warning",{},[3829,4477,4478],{},"Важливо:"," ",[3769,4481,3865],{}," має бути ",[3829,4484,4485],{},"найвищим"," компонентом в ієрархії, щоб усі дочірні компоненти мали доступ до Redux store через хуки ",[3769,4488,3868],{},[3769,4490,3872],{},[3743,4492,4493],{},"Тепер ваш проєкт готовий до роботи з Redux Toolkit! У наступних розділах ми розглянемо, як створювати slices, працювати з даними та будувати складні застосунки.",[4495,4496],"hr",{},[3738,4498,4500],{"id":4499},"навіщо-централізоване-сховище-на-мобільному-пристрої","Навіщо централізоване сховище на мобільному пристрої",[3743,4502,4503],{},"Уявіть, що ви розробляєте складний мобільний продукт: стрічка поїздок, екран детального перегляду маршруту, модальне вікно створення нової локації, панель фільтрації, екран профілю користувача з налаштуваннями теми та офлайн-сховище. Кожен із цих екранів потребує доступу до спільних даних: зміна статусу поїздки в деталях повинна миттєво відобразитися у стрічці, а оновлення теми в налаштуваннях має без затримок перефарбувати всі навігаційні панелі.",[3743,4505,4506,4507,4511,4512,4514],{},"У веб-розробці для цього застосовують локальний стан компонентів, підняття стану вгору (",[4508,4509,4510],"em",{},"Lifting State Up","), Context API або глобальні стейт-менеджери. Проте в мобільному середовищі на ",[3829,4513,3361],{}," з'являються критичні фактори, які роблять архітектуру керування станом значно складнішою:",[4516,4517,4518,4536,4544,4552],"field-group",{},[4519,4520,4523,4524,4527,4528,4531,4532,4535],"field",{"name":4521,"type":4522},"1. Життєвий цикл навігаційного стека (Navigation Stack Lifecycle)","Мобільний фактор","На відміну від браузера, де перехід за посиланням зазвичай розмонтовує попередню сторінку, стек мобільної навігації (наприклад, у React Navigation або Expo Router) зберігає попередні екрани ",[3829,4525,4526],{},"змонтованими у пам'яті",", щоб забезпечити миттєву анімацію жесту повернення назад (",[4508,4529,4530],{},"Swipe Back","). Якщо стан зберігається локально в ",[3769,4533,4534],{},"useState"," одного з екранів, спроба оновити його з модального вікна вимагає громіздкого передавання колбеків крізь навігаційні параметри, що призводить до заплутаного коду та витоків пам'яті.",[4519,4537,4539,4540,4543],{"name":4538,"type":4522},"2. Обмеженість пам'яті та примусове вивантаження процесу (OOM Killer)","Мобільна операційна система (iOS чи Android) у будь-який момент може примусово «вбити» фоновий процес застосунку для вивільнення оперативної пам'яті для вхідного дзвінка або камери. При поверненні користувача JavaScript-рантайм запускається «з нуля». Централізоване сховище дозволяє легко налаштувати ",[3829,4541,4542],{},"персистентність (State Rehydration)"," — автоматичне збереження та відновлення всього дерева стану з дискового сховища (MMKV або AsyncStorage).",[4519,4545,4547,4548,4551],{"name":4546,"type":4522},"3. Асинхронні ланцюжки та робота в нестабільній мережі","Мобільні застосунки постійно виконують паралельні асинхронні задачі: запити до API, фонове визначення геолокації, читання з локальної бази SQLite та роботу в режимі офлайн. Без жорстко структурованого потоку даних застосунок швидко скочується до стану гонитви (",[4508,4549,4550],{},"Race Conditions",") та неконсистентності UI.",[4519,4553,4555,4556,4559],{"name":4554,"type":4522},"4. Дебаг та інспектування стану у виробничому середовищі","Дебаг мобільного клієнта на реальному фізичному пристрої значно складніший за веб-інспектор. Інтеграція Redux DevTools дозволяє записувати історію дій, досліджувати знімки пам'яті та проводити перемотування стану (",[4508,4557,4558],{},"Time-Travel Debugging",") безпосередньо під час тестування жестів та переходів.",[3875,4561,4562,4565,4566,4569,4570,4573],{},[3829,4563,4564],{},"Головний висновок:"," Централізоване сховище в мобільному застосунку є ",[3829,4567,4568],{},"єдиним джерелом істини (Single Source of Truth)",", що відокремлює бізнес-логіку та роботу з даними від візуального життєвого циклу екранів. ",[3829,4571,4572],{},"Redux Toolkit (RTK)"," є офіційним стандартом Redux, який усуває понад 80% шаблонного коду, гарантує безпеку типізації та оптимізує рендеринг за рахунок поверхневого порівняння селекторів.",[4495,4575],{},[3738,4577,4579],{"id":4578},"що-таке-redux-toolkit-еволюція-та-архітектурні-переваги","Що таке Redux Toolkit: Еволюція та архітектурні переваги",[3747,4581,4583],{"id":4582},"історія-та-еволюція-від-legacy-redux-до-rtk","Історія та еволюція від Legacy Redux до RTK",[3743,4585,4586],{},"Класичний Redux, створений Деном Абрамовим у 2015 році, базувався на трьох базових принципах:",[4588,4589,4590,4596,4606],"ol",{},[3836,4591,4592,4595],{},[3829,4593,4594],{},"Єдине джерело істини:"," Весь глобальний стан зберігається в єдиному дереві всередині одного Store.",[3836,4597,4598,4601,4602,4605],{},[3829,4599,4600],{},"Стан доступний лише для читання:"," Єдиний спосіб змінити стан — відправити дію (",[3829,4603,4604],{},"Action","), що описує подію, яка відбулася.",[3836,4607,4608,4611,4612,4615],{},[3829,4609,4610],{},"Зміни вносяться чистими функціями:"," Логіка оновлення стану описується ",[3829,4613,4614],{},"Редюсерами (Reducers)",", які приймають поточний стан і дію та повертають новий стан без побічних ефектів.",[3743,4617,4618,4619,4622],{},"Незважаючи на просту концепцію, класичний «Legacy Redux» мав великий мінус — ",[3829,4620,4621],{},"величезну кількість шаблонного коду (Boilerplate)",". Для додавання навіть простого поля потрібно було:",[3833,4624,4625,4632,4638,4645,4655],{},[3836,4626,4627,4628,4631],{},"Створити строкову константу ",[3769,4629,4630],{},"const ADD_TRIP = 'trips\u002FADD_TRIP'",";",[3836,4633,4634,4635,4631],{},"Написати функцію-творець дії ",[3769,4636,4637],{},"const addTrip = (trip) => ({ type: ADD_TRIP, payload: trip })",[3836,4639,4640,4641,4644],{},"Описати громіздкий ",[3769,4642,4643],{},"switch\u002Fcase"," у файлі редюсера;",[3836,4646,4647,4648,3847,4651,4654],{},"Вручну копіювати кожен рівень вкладеності через spread-оператори (",[3769,4649,4650],{},"...state",[3769,4652,4653],{},"...state.items","), щоб не порушити іммутабельність;",[3836,4656,4657,4658,4660],{},"Вручну налаштовувати підключення ",[3769,4659,4105],{},", DevTools extension та middleware для перевірки мутацій.",[3743,4662,4663,4664,4670],{},"У 2019 році команда розробників випустила ",[3829,4665,4666,4667,4669],{},"Redux Toolkit (",[3769,4668,3842],{},")",", що повністю переосмислив досвід роботи з Redux:",[3762,4672,4675],{"className":4673,"code":4674,"language":3910},[3908],"┌──────────────────────────────────────────────────────────────────────────────────────────┐\n│                                 REDUX TOOLKIT (RTK)                                      │\n├──────────────────────────┬───────────────────────────────┬───────────────────────────────┤\n│    configureStore()      │        createSlice()          │      createAsyncThunk()       │\n│  Автоматичний thunk,     │  Об'єднує Actions + Reducers  │  Стандартизує async lifecycle │\n│  DevTools та middleware  │   з підтримкою Immer Proxy    │   (pending\u002Ffulfilled\u002Frejected)│\n├──────────────────────────┼───────────────────────────────┼───────────────────────────────┤\n│  createEntityAdapter()   │       createSelector()        │   createListenerMiddleware()  │\n│   Нормалізація O(1)      │      Reselect мемоїзація      │    Легковагі сайд-ефекти      │\n│  (byId + allIds CRUD)    │    для важких списків RN      │    замість важкої Saga        │\n└──────────────────────────┴───────────────────────────────┴───────────────────────────────┘\n",[3769,4676,4674],{"__ignoreMap":3767},[4495,4678],{},[3738,4680,4682],{"id":4681},"базові-концепції-redux-нагадування-основ","Базові концепції Redux: Нагадування основ",[3743,4684,4685],{},"Перед тим як заглибитися у Redux Toolkit, важливо чітко розуміти три фундаментальні концепції Redux, на яких побудована вся архітектура.",[3747,4687,4689],{"id":4688},"що-таке-store-сховище","Що таке Store (Сховище)?",[3743,4691,4692,4695,4696,4699],{},[3829,4693,4694],{},"Store"," — це центральний об'єкт, який зберігає ",[3829,4697,4698],{},"весь"," глобальний стан вашого застосунку у вигляді єдиного JavaScript-об'єкта. Уявіть його як велику базу даних в пам'яті.",[3762,4701,4703],{"className":3925,"code":4702,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Приклад стану у Store\n{\n    trips: {\n        items: [\n            { id: '1', title: 'Карпати', region: 'Захід' },\n            { id: '2', title: 'Одеса', region: 'Південь' }\n        ],\n        loading: false,\n        error: null\n    },\n    user: {\n        profile: { name: 'Олександр', email: 'alex@example.com' },\n        isAuthenticated: true\n    },\n    settings: {\n        theme: 'dark',\n        language: 'uk'\n    }\n}\n",[3769,4704,4705,4710,4715,4724,4732,4762,4788,4793,4807,4817,4821,4828,4856,4866,4870,4877,4890,4901,4907],{"__ignoreMap":3767},[3772,4706,4707],{"class":3774,"line":3775},[3772,4708,4709],{"class":3934},"\u002F\u002F Приклад стану у Store\n",[3772,4711,4712],{"class":3774,"line":3938},[3772,4713,4714],{"class":3945},"{\n",[3772,4716,4717,4721],{"class":3774,"line":3961},[3772,4718,4720],{"class":4719},"s5IvJ","    trips",[3772,4722,4723],{"class":3945},": {\n",[3772,4725,4726,4729],{"class":3774,"line":3968},[3772,4727,4728],{"class":4719},"        items",[3772,4730,4731],{"class":3945},": [\n",[3772,4733,4734,4737,4740,4743,4745,4748,4751,4753,4756,4759],{"class":3774,"line":3974},[3772,4735,4736],{"class":3945},"            { ",[3772,4738,4739],{"class":3949},"id:",[3772,4741,4742],{"class":3781}," '1'",[3772,4744,3847],{"class":3945},[3772,4746,4747],{"class":3949},"title:",[3772,4749,4750],{"class":3781}," 'Карпати'",[3772,4752,3847],{"class":3945},[3772,4754,4755],{"class":3949},"region:",[3772,4757,4758],{"class":3781}," 'Захід'",[3772,4760,4761],{"class":3945}," },\n",[3772,4763,4764,4766,4768,4771,4773,4775,4778,4780,4782,4785],{"class":3774,"line":3996},[3772,4765,4736],{"class":3945},[3772,4767,4739],{"class":3949},[3772,4769,4770],{"class":3781}," '2'",[3772,4772,3847],{"class":3945},[3772,4774,4747],{"class":3949},[3772,4776,4777],{"class":3781}," 'Одеса'",[3772,4779,3847],{"class":3945},[3772,4781,4755],{"class":3949},[3772,4783,4784],{"class":3781}," 'Південь'",[3772,4786,4787],{"class":3945}," }\n",[3772,4789,4790],{"class":3774,"line":4005},[3772,4791,4792],{"class":3945},"        ],\n",[3772,4794,4795,4798,4801,4804],{"class":3774,"line":4011},[3772,4796,4797],{"class":4719},"        loading",[3772,4799,4800],{"class":3945},": ",[3772,4802,4803],{"class":3980},"false",[3772,4805,4806],{"class":3945},",\n",[3772,4808,4809,4812,4814],{"class":3774,"line":4017},[3772,4810,4811],{"class":4719},"        error",[3772,4813,4800],{"class":3945},[3772,4815,4816],{"class":3980},"null\n",[3772,4818,4819],{"class":3774,"line":4023},[3772,4820,4014],{"class":3945},[3772,4822,4823,4826],{"class":3774,"line":4028},[3772,4824,4825],{"class":4719},"    user",[3772,4827,4723],{"class":3945},[3772,4829,4830,4833,4836,4839,4841,4844,4846,4849,4851,4854],{"class":3774,"line":4034},[3772,4831,4832],{"class":4719},"        profile",[3772,4834,4835],{"class":3945},": { ",[3772,4837,4838],{"class":4719},"name",[3772,4840,4800],{"class":3945},[3772,4842,4843],{"class":3781},"'Олександр'",[3772,4845,3847],{"class":3945},[3772,4847,4848],{"class":4719},"email",[3772,4850,4800],{"class":3945},[3772,4852,4853],{"class":3781},"'alex@example.com'",[3772,4855,4761],{"class":3945},[3772,4857,4858,4861,4863],{"class":3774,"line":4068},[3772,4859,4860],{"class":4719},"        isAuthenticated",[3772,4862,4800],{"class":3945},[3772,4864,4865],{"class":3980},"true\n",[3772,4867,4868],{"class":3774,"line":4313},[3772,4869,4014],{"class":3945},[3772,4871,4872,4875],{"class":3774,"line":4470},[3772,4873,4874],{"class":4719},"    settings",[3772,4876,4723],{"class":3945},[3772,4878,4880,4883,4885,4888],{"class":3774,"line":4879},16,[3772,4881,4882],{"class":4719},"        theme",[3772,4884,4800],{"class":3945},[3772,4886,4887],{"class":3781},"'dark'",[3772,4889,4806],{"class":3945},[3772,4891,4893,4896,4898],{"class":3774,"line":4892},17,[3772,4894,4895],{"class":4719},"        language",[3772,4897,4800],{"class":3945},[3772,4899,4900],{"class":3781},"'uk'\n",[3772,4902,4904],{"class":3774,"line":4903},18,[3772,4905,4906],{"class":3945},"    }\n",[3772,4908,4910],{"class":3774,"line":4909},19,[3772,4911,4316],{"class":3945},[3743,4913,4914],{},[3829,4915,4916],{},"Головні правила Store:",[4588,4918,4919,4926,4933],{},[3836,4920,4921,4922,4925],{},"У застосунку має бути ",[3829,4923,4924],{},"лише один"," Store (Single Source of Truth)",[3836,4927,4928,4929,4932],{},"Стан Store ",[3829,4930,4931],{},"доступний лише для читання"," — не можна змінювати його напряму",[3836,4934,4935,4936,4938],{},"Єдиний спосіб змінити стан — відправити ",[3829,4937,4604],{}," (дію)",[3747,4940,4942],{"id":4941},"що-таке-action-дія","Що таке Action (Дія)?",[3743,4944,4945,4947,4948,4951],{},[3829,4946,4604],{}," — це звичайний JavaScript-об'єкт, який описує ",[3829,4949,4950],{},"що саме сталося"," у застосунку. Це як повідомлення або команда.",[3762,4953,4955],{"className":3925,"code":4954,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Приклад простої дії\n{\n    type: 'trips\u002FaddTrip',           \u002F\u002F Тип дії (обов'язковий)\n    payload: {                        \u002F\u002F Дані дії (опціонально)\n        id: '3',\n        title: 'Київ',\n        region: 'Центр'\n    }\n}\n",[3769,4956,4957,4962,4966,4982,4993,5005,5017,5027,5031],{"__ignoreMap":3767},[3772,4958,4959],{"class":3774,"line":3775},[3772,4960,4961],{"class":3934},"\u002F\u002F Приклад простої дії\n",[3772,4963,4964],{"class":3774,"line":3938},[3772,4965,4714],{"class":3945},[3772,4967,4968,4971,4973,4976,4979],{"class":3774,"line":3961},[3772,4969,4970],{"class":4719},"    type",[3772,4972,4800],{"class":3945},[3772,4974,4975],{"class":3781},"'trips\u002FaddTrip'",[3772,4977,4978],{"class":3945},",           ",[3772,4980,4981],{"class":3934},"\u002F\u002F Тип дії (обов'язковий)\n",[3772,4983,4984,4987,4990],{"class":3774,"line":3968},[3772,4985,4986],{"class":4719},"    payload",[3772,4988,4989],{"class":3945},": {                        ",[3772,4991,4992],{"class":3934},"\u002F\u002F Дані дії (опціонально)\n",[3772,4994,4995,4998,5000,5003],{"class":3774,"line":3974},[3772,4996,4997],{"class":4719},"        id",[3772,4999,4800],{"class":3945},[3772,5001,5002],{"class":3781},"'3'",[3772,5004,4806],{"class":3945},[3772,5006,5007,5010,5012,5015],{"class":3774,"line":3996},[3772,5008,5009],{"class":4719},"        title",[3772,5011,4800],{"class":3945},[3772,5013,5014],{"class":3781},"'Київ'",[3772,5016,4806],{"class":3945},[3772,5018,5019,5022,5024],{"class":3774,"line":4005},[3772,5020,5021],{"class":4719},"        region",[3772,5023,4800],{"class":3945},[3772,5025,5026],{"class":3781},"'Центр'\n",[3772,5028,5029],{"class":3774,"line":4011},[3772,5030,4906],{"class":3945},[3772,5032,5033],{"class":3774,"line":4017},[3772,5034,4316],{"class":3945},[3743,5036,5037],{},[3829,5038,5039],{},"Анатомія Action:",[3833,5041,5042,5053,5061],{},[3836,5043,5044,5049,5050],{},[3829,5045,5046],{},[3769,5047,5048],{},"type"," (обов'язковий) — унікальний рядок, що ідентифікує подію. Зазвичай у форматі ",[3769,5051,5052],{},"'sliceName\u002FactionName'",[3836,5054,5055,5060],{},[3829,5056,5057],{},[3769,5058,5059],{},"payload"," (опціонально) — дані, які потрібні для обробки цієї дії",[3836,5062,5063,3847,5068,5073],{},[3829,5064,5065],{},[3769,5066,5067],{},"meta",[3829,5069,5070],{},[3769,5071,5072],{},"error"," (опціонально) — додаткові поля для метаданих або помилок",[5075,5076,5077,5087,5106],"tip",{},[3743,5078,5079,5082,5083,5086],{},[3829,5080,5081],{},"Називання дій:"," Використовуйте формат ",[3769,5084,5085],{},"'domain\u002FeventType'",", наприклад:",[3833,5088,5089,5094,5100],{},[3836,5090,5091,5093],{},[3769,5092,4975],{}," — додати поїздку",[3836,5095,5096,5099],{},[3769,5097,5098],{},"'user\u002FloginSuccess'"," — успішний логін",[3836,5101,5102,5105],{},[3769,5103,5104],{},"'settings\u002FtoggleTheme'"," — перемкнути тему",[3743,5107,5108],{},"Це допомагає швидко зрозуміти, до якої частини застосунку належить дія.",[3747,5110,5112],{"id":5111},"що-таке-reducer-редюсер","Що таке Reducer (Редюсер)?",[3743,5114,5115,5118,5119,3869,5122,5125,5126,5129],{},[3829,5116,5117],{},"Reducer"," — це чиста функція, яка приймає ",[3829,5120,5121],{},"поточний стан",[3829,5123,5124],{},"дію",", і повертає ",[3829,5127,5128],{},"новий стан",". Це єдине місце, де дозволено змінювати стан.",[3762,5131,5133],{"className":3925,"code":5132,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Простий приклад редюсера (без Redux Toolkit)\nfunction tripsReducer(state = initialState, action) {\n    \u002F\u002F Перевіряємо тип дії\n    if (action.type === 'trips\u002FaddTrip') {\n        \u002F\u002F Повертаємо НОВИЙ стан (не мутуємо старий!)\n        return {\n            ...state,\n            items: [action.payload, ...state.items],\n        }\n    }\n\n    \u002F\u002F Якщо дія не для нас — повертаємо стан без змін\n    return state\n}\n",[3769,5134,5135,5140,5167,5172,5193,5198,5205,5214,5241,5246,5250,5254,5259,5266],{"__ignoreMap":3767},[3772,5136,5137],{"class":3774,"line":3775},[3772,5138,5139],{"class":3934},"\u002F\u002F Простий приклад редюсера (без Redux Toolkit)\n",[3772,5141,5142,5145,5148,5151,5154,5156,5159,5161,5164],{"class":3774,"line":3938},[3772,5143,5144],{"class":3980},"function",[3772,5146,5147],{"class":3778}," tripsReducer",[3772,5149,5150],{"class":3945},"(",[3772,5152,5153],{"class":3949},"state",[3772,5155,3988],{"class":3945},[3772,5157,5158],{"class":3949},"initialState",[3772,5160,3847],{"class":3945},[3772,5162,5163],{"class":3949},"action",[3772,5165,5166],{"class":3945},") {\n",[3772,5168,5169],{"class":3774,"line":3961},[3772,5170,5171],{"class":3934},"    \u002F\u002F Перевіряємо тип дії\n",[3772,5173,5174,5177,5180,5182,5184,5186,5189,5191],{"class":3774,"line":3968},[3772,5175,5176],{"class":3941},"    if",[3772,5178,5179],{"class":3945}," (",[3772,5181,5163],{"class":3949},[3772,5183,4059],{"class":3945},[3772,5185,5048],{"class":3949},[3772,5187,5188],{"class":3945}," === ",[3772,5190,4975],{"class":3781},[3772,5192,5166],{"class":3945},[3772,5194,5195],{"class":3774,"line":3974},[3772,5196,5197],{"class":3934},"        \u002F\u002F Повертаємо НОВИЙ стан (не мутуємо старий!)\n",[3772,5199,5200,5203],{"class":3774,"line":3996},[3772,5201,5202],{"class":3941},"        return",[3772,5204,4002],{"class":3945},[3772,5206,5207,5210,5212],{"class":3774,"line":4005},[3772,5208,5209],{"class":3945},"            ...",[3772,5211,5153],{"class":3949},[3772,5213,4806],{"class":3945},[3772,5215,5216,5219,5222,5224,5226,5228,5231,5233,5235,5238],{"class":3774,"line":4011},[3772,5217,5218],{"class":3949},"            items:",[3772,5220,5221],{"class":3945}," [",[3772,5223,5163],{"class":3949},[3772,5225,4059],{"class":3945},[3772,5227,5059],{"class":3949},[3772,5229,5230],{"class":3945},", ...",[3772,5232,5153],{"class":3949},[3772,5234,4059],{"class":3945},[3772,5236,5237],{"class":3949},"items",[3772,5239,5240],{"class":3945},"],\n",[3772,5242,5243],{"class":3774,"line":4017},[3772,5244,5245],{"class":3945},"        }\n",[3772,5247,5248],{"class":3774,"line":4023},[3772,5249,4906],{"class":3945},[3772,5251,5252],{"class":3774,"line":4028},[3772,5253,3965],{"emptyLinePlaceholder":3964},[3772,5255,5256],{"class":3774,"line":4034},[3772,5257,5258],{"class":3934},"    \u002F\u002F Якщо дія не для нас — повертаємо стан без змін\n",[3772,5260,5261,5263],{"class":3774,"line":4068},[3772,5262,4210],{"class":3941},[3772,5264,5265],{"class":3949}," state\n",[3772,5267,5268],{"class":3774,"line":4313},[3772,5269,4316],{"class":3945},[3743,5271,5272],{},[3829,5273,5274],{},"Правила Reducer:",[4588,5276,5277,5283,5292],{},[3836,5278,5279,5282],{},[3829,5280,5281],{},"Чиста функція"," — однакові вхідні дані завжди дають однаковий результат",[3836,5284,5285,5288,5289,5291],{},[3829,5286,5287],{},"Іммутабельність"," — ніколи не змінюємо вхідний ",[3769,5290,5153],{}," напряму, завжди створюємо новий",[3836,5293,5294,5297],{},[3829,5295,5296],{},"Без побічних ефектів"," — не робимо HTTP-запити, не змінюємо глобальні змінні, не генеруємо випадкові числа",[3875,5299,5300,5305,5315],{},[3743,5301,5302],{},[3829,5303,5304],{},"Чому іммутабельність важлива?",[3743,5306,5307,5308,5179,5311,5314],{},"React і Redux порівнюють стан за ",[3829,5309,5310],{},"посиланням",[3769,5312,5313],{},"oldState === newState","), а не за вмістом. Якщо ви змінюєте об'єкт напряму (мутуєте), посилання залишається тим самим, і React не помітить змін — компонент не оновиться.",[3762,5316,5318],{"className":3925,"code":5317,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОГАНО: Мутація (посилання не змінилося)\nstate.items.push(newItem)\nreturn state \u002F\u002F Той самий об'єкт!\n\n\u002F\u002F ✅ ДОБРЕ: Створюємо новий масив\nreturn {\n    ...state,\n    items: [...state.items, newItem], \u002F\u002F Нове посилання!\n}\n",[3769,5319,5320,5325,5346,5357,5361,5366,5372,5381,5405],{"__ignoreMap":3767},[3772,5321,5322],{"class":3774,"line":3775},[3772,5323,5324],{"class":3934},"\u002F\u002F ❌ ПОГАНО: Мутація (посилання не змінилося)\n",[3772,5326,5327,5329,5331,5333,5335,5338,5340,5343],{"class":3774,"line":3938},[3772,5328,5153],{"class":3949},[3772,5330,4059],{"class":3945},[3772,5332,5237],{"class":3949},[3772,5334,4059],{"class":3945},[3772,5336,5337],{"class":3778},"push",[3772,5339,5150],{"class":3945},[3772,5341,5342],{"class":3949},"newItem",[3772,5344,5345],{"class":3945},")\n",[3772,5347,5348,5351,5354],{"class":3774,"line":3961},[3772,5349,5350],{"class":3941},"return",[3772,5352,5353],{"class":3949}," state",[3772,5355,5356],{"class":3934}," \u002F\u002F Той самий об'єкт!\n",[3772,5358,5359],{"class":3774,"line":3968},[3772,5360,3965],{"emptyLinePlaceholder":3964},[3772,5362,5363],{"class":3774,"line":3974},[3772,5364,5365],{"class":3934},"\u002F\u002F ✅ ДОБРЕ: Створюємо новий масив\n",[3772,5367,5368,5370],{"class":3774,"line":3996},[3772,5369,5350],{"class":3941},[3772,5371,4002],{"class":3945},[3772,5373,5374,5377,5379],{"class":3774,"line":4005},[3772,5375,5376],{"class":3945},"    ...",[3772,5378,5153],{"class":3949},[3772,5380,4806],{"class":3945},[3772,5382,5383,5386,5389,5391,5393,5395,5397,5399,5402],{"class":3774,"line":4011},[3772,5384,5385],{"class":3949},"    items:",[3772,5387,5388],{"class":3945}," [...",[3772,5390,5153],{"class":3949},[3772,5392,4059],{"class":3945},[3772,5394,5237],{"class":3949},[3772,5396,3847],{"class":3945},[3772,5398,5342],{"class":3949},[3772,5400,5401],{"class":3945},"], ",[3772,5403,5404],{"class":3934},"\u002F\u002F Нове посилання!\n",[3772,5406,5407],{"class":3774,"line":4017},[3772,5408,4316],{"class":3945},[3747,5410,5412],{"id":5411},"життєвий-цикл-даних-у-redux","Життєвий цикл даних у Redux",[3743,5414,5415],{},"Тепер з'єднаємо все разом та подивимось, як дані рухаються через Redux:",[5417,5418,5420],"plant-uml",{"alt":5419},"Життєвий цикл Redux",[3762,5421,5425],{"className":5422,"code":5423,"language":5424,"meta":3767,"style":3767},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam defaultFontName \"Helvetica\"\n\nactor \"Користувач\" as User #DBEAFE\nparticipant \"UI (React Component)\" as UI #DCFCE7\nparticipant \"Action\" as Action #FEF08A\nparticipant \"Reducer\" as Reducer #FED7AA\ndatabase \"Store (State)\" as Store #E0E7FF\n\nUser -> UI : 1. Натискає кнопку\\n\"Додати поїздку\"\nUI -> Action : 2. dispatch(addTrip({...}))\nAction -> Reducer : 3. Передає дію в редюсер\nReducer -> Reducer : 4. Обчислює новий стан\nReducer -> Store : 5. Зберігає новий стан\nStore -> UI : 6. Сповіщає компонент\\nпро зміну (useSelector)\nUI -> User : 7. Ререндер з новими даними\n\nnote over Reducer #FEF3C7\n    Reducer — чиста функція:\n    newState = reducer(oldState, action)\nend note\n\n@enduml\n","plantuml",[3769,5426,5427,5432,5437,5442,5447,5451,5456,5461,5466,5471,5476,5480,5485,5490,5495,5500,5505,5510,5515,5519,5525,5531,5537,5543,5548],{"__ignoreMap":3767},[3772,5428,5429],{"class":3774,"line":3775},[3772,5430,5431],{},"@startuml\n",[3772,5433,5434],{"class":3774,"line":3938},[3772,5435,5436],{},"skinparam style plain\n",[3772,5438,5439],{"class":3774,"line":3961},[3772,5440,5441],{},"skinparam backgroundColor #ffffff\n",[3772,5443,5444],{"class":3774,"line":3968},[3772,5445,5446],{},"skinparam defaultFontName \"Helvetica\"\n",[3772,5448,5449],{"class":3774,"line":3974},[3772,5450,3965],{"emptyLinePlaceholder":3964},[3772,5452,5453],{"class":3774,"line":3996},[3772,5454,5455],{},"actor \"Користувач\" as User #DBEAFE\n",[3772,5457,5458],{"class":3774,"line":4005},[3772,5459,5460],{},"participant \"UI (React Component)\" as UI #DCFCE7\n",[3772,5462,5463],{"class":3774,"line":4011},[3772,5464,5465],{},"participant \"Action\" as Action #FEF08A\n",[3772,5467,5468],{"class":3774,"line":4017},[3772,5469,5470],{},"participant \"Reducer\" as Reducer #FED7AA\n",[3772,5472,5473],{"class":3774,"line":4023},[3772,5474,5475],{},"database \"Store (State)\" as Store #E0E7FF\n",[3772,5477,5478],{"class":3774,"line":4028},[3772,5479,3965],{"emptyLinePlaceholder":3964},[3772,5481,5482],{"class":3774,"line":4034},[3772,5483,5484],{},"User -> UI : 1. Натискає кнопку\\n\"Додати поїздку\"\n",[3772,5486,5487],{"class":3774,"line":4068},[3772,5488,5489],{},"UI -> Action : 2. dispatch(addTrip({...}))\n",[3772,5491,5492],{"class":3774,"line":4313},[3772,5493,5494],{},"Action -> Reducer : 3. Передає дію в редюсер\n",[3772,5496,5497],{"class":3774,"line":4470},[3772,5498,5499],{},"Reducer -> Reducer : 4. Обчислює новий стан\n",[3772,5501,5502],{"class":3774,"line":4879},[3772,5503,5504],{},"Reducer -> Store : 5. Зберігає новий стан\n",[3772,5506,5507],{"class":3774,"line":4892},[3772,5508,5509],{},"Store -> UI : 6. Сповіщає компонент\\nпро зміну (useSelector)\n",[3772,5511,5512],{"class":3774,"line":4903},[3772,5513,5514],{},"UI -> User : 7. Ререндер з новими даними\n",[3772,5516,5517],{"class":3774,"line":4909},[3772,5518,3965],{"emptyLinePlaceholder":3964},[3772,5520,5522],{"class":3774,"line":5521},20,[3772,5523,5524],{},"note over Reducer #FEF3C7\n",[3772,5526,5528],{"class":3774,"line":5527},21,[3772,5529,5530],{},"    Reducer — чиста функція:\n",[3772,5532,5534],{"class":3774,"line":5533},22,[3772,5535,5536],{},"    newState = reducer(oldState, action)\n",[3772,5538,5540],{"class":3774,"line":5539},23,[3772,5541,5542],{},"end note\n",[3772,5544,5546],{"class":3774,"line":5545},24,[3772,5547,3965],{"emptyLinePlaceholder":3964},[3772,5549,5551],{"class":3774,"line":5550},25,[3772,5552,5553],{},"@enduml\n",[3743,5555,5556],{},[3829,5557,5558],{},"Покроковий опис:",[4588,5560,5561,5567,5576,5582,5588,5594,5603],{},[3836,5562,5563,5566],{},[3829,5564,5565],{},"Користувач діє"," — натискає кнопку, вводить текст тощо",[3836,5568,5569,5572,5573],{},[3829,5570,5571],{},"Компонент відправляє дію"," — ",[3769,5574,5575],{},"dispatch(addTrip({ title: 'Київ' }))",[3836,5577,5578,5581],{},[3829,5579,5580],{},"Store передає дію в Reducer"," — викликає функцію редюсера з поточним станом",[3836,5583,5584,5587],{},[3829,5585,5586],{},"Reducer обчислює новий стан"," — обробляє дію та повертає оновлений стан",[3836,5589,5590,5593],{},[3829,5591,5592],{},"Store зберігає новий стан"," — замінює старий стан на новий",[3836,5595,5596,5599,5600,5602],{},[3829,5597,5598],{},"Store сповіщає підписників"," — усі компоненти з ",[3769,5601,3868],{}," отримують нотифікацію",[3836,5604,5605,5608],{},[3829,5606,5607],{},"React ререндерить компоненти"," — які використовують змінені дані",[4495,5610],{},[3738,5612,5614],{"id":5613},"що-таке-redux-toolkit-та-навіщо-він-потрібен","Що таке Redux Toolkit та навіщо він потрібен?",[3743,5616,5617],{},"Тепер, коли ми пригадали основи Redux, поговоримо про те, чому був створений Redux Toolkit.",[3747,5619,2199],{"id":5620},"проблеми-класичного-redux",[3743,5622,5623,5624,5627],{},"У «старому» Redux (який ще називають Legacy Redux) для додавання простої функції додавання поїздки потрібно було написати ",[3829,5625,5626],{},"багато"," коду:",[5629,5630,5631,5712,5840,6165],"code-group",{},[3762,5632,5635],{"className":3925,"code":5633,"filename":5634,"language":3927,"meta":3767,"style":3767},"\u002F\u002F constants\u002FactionTypes.ts\nexport const ADD_TRIP = 'trips\u002FADD_TRIP'\nexport const REMOVE_TRIP = 'trips\u002FREMOVE_TRIP'\nexport const FETCH_TRIPS_START = 'trips\u002FFETCH_TRIPS_START'\nexport const FETCH_TRIPS_SUCCESS = 'trips\u002FFETCH_TRIPS_SUCCESS'\nexport const FETCH_TRIPS_FAILURE = 'trips\u002FFETCH_TRIPS_FAILURE'\n","1. Константи типів",[3769,5636,5637,5642,5656,5670,5684,5698],{"__ignoreMap":3767},[3772,5638,5639],{"class":3774,"line":3775},[3772,5640,5641],{"class":3934},"\u002F\u002F constants\u002FactionTypes.ts\n",[3772,5643,5644,5646,5648,5651,5653],{"class":3774,"line":3938},[3772,5645,3977],{"class":3941},[3772,5647,3981],{"class":3980},[3772,5649,5650],{"class":3984}," ADD_TRIP",[3772,5652,3988],{"class":3945},[3772,5654,5655],{"class":3781},"'trips\u002FADD_TRIP'\n",[3772,5657,5658,5660,5662,5665,5667],{"class":3774,"line":3961},[3772,5659,3977],{"class":3941},[3772,5661,3981],{"class":3980},[3772,5663,5664],{"class":3984}," REMOVE_TRIP",[3772,5666,3988],{"class":3945},[3772,5668,5669],{"class":3781},"'trips\u002FREMOVE_TRIP'\n",[3772,5671,5672,5674,5676,5679,5681],{"class":3774,"line":3968},[3772,5673,3977],{"class":3941},[3772,5675,3981],{"class":3980},[3772,5677,5678],{"class":3984}," FETCH_TRIPS_START",[3772,5680,3988],{"class":3945},[3772,5682,5683],{"class":3781},"'trips\u002FFETCH_TRIPS_START'\n",[3772,5685,5686,5688,5690,5693,5695],{"class":3774,"line":3974},[3772,5687,3977],{"class":3941},[3772,5689,3981],{"class":3980},[3772,5691,5692],{"class":3984}," FETCH_TRIPS_SUCCESS",[3772,5694,3988],{"class":3945},[3772,5696,5697],{"class":3781},"'trips\u002FFETCH_TRIPS_SUCCESS'\n",[3772,5699,5700,5702,5704,5707,5709],{"class":3774,"line":3996},[3772,5701,3977],{"class":3941},[3772,5703,3981],{"class":3980},[3772,5705,5706],{"class":3984}," FETCH_TRIPS_FAILURE",[3772,5708,3988],{"class":3945},[3772,5710,5711],{"class":3781},"'trips\u002FFETCH_TRIPS_FAILURE'\n",[3762,5713,5716],{"className":3925,"code":5714,"filename":5715,"language":3927,"meta":3767,"style":3767},"\u002F\u002F actions\u002FtripsActions.ts\nimport { ADD_TRIP, REMOVE_TRIP } from '..\u002Fconstants\u002FactionTypes'\n\nexport const addTrip = (trip) => ({\n    type: ADD_TRIP,\n    payload: trip,\n})\n\nexport const removeTrip = (id) => ({\n    type: REMOVE_TRIP,\n    payload: id,\n})\n","2. Action Creators",[3769,5717,5718,5723,5744,5748,5772,5781,5791,5795,5799,5819,5827,5836],{"__ignoreMap":3767},[3772,5719,5720],{"class":3774,"line":3775},[3772,5721,5722],{"class":3934},"\u002F\u002F actions\u002FtripsActions.ts\n",[3772,5724,5725,5727,5729,5732,5734,5737,5739,5741],{"class":3774,"line":3938},[3772,5726,3942],{"class":3941},[3772,5728,3946],{"class":3945},[3772,5730,5731],{"class":3949},"ADD_TRIP",[3772,5733,3847],{"class":3945},[3772,5735,5736],{"class":3949},"REMOVE_TRIP",[3772,5738,3952],{"class":3945},[3772,5740,3955],{"class":3941},[3772,5742,5743],{"class":3781}," '..\u002Fconstants\u002FactionTypes'\n",[3772,5745,5746],{"class":3774,"line":3961},[3772,5747,3965],{"emptyLinePlaceholder":3964},[3772,5749,5750,5752,5754,5757,5760,5763,5766,5769],{"class":3774,"line":3968},[3772,5751,3977],{"class":3941},[3772,5753,3981],{"class":3980},[3772,5755,5756],{"class":3778}," addTrip",[3772,5758,5759],{"class":3945}," = (",[3772,5761,5762],{"class":3949},"trip",[3772,5764,5765],{"class":3945},") ",[3772,5767,5768],{"class":3980},"=>",[3772,5770,5771],{"class":3945}," ({\n",[3772,5773,5774,5777,5779],{"class":3774,"line":3974},[3772,5775,5776],{"class":3949},"    type:",[3772,5778,5650],{"class":3984},[3772,5780,4806],{"class":3945},[3772,5782,5783,5786,5789],{"class":3774,"line":3996},[3772,5784,5785],{"class":3949},"    payload:",[3772,5787,5788],{"class":3949}," trip",[3772,5790,4806],{"class":3945},[3772,5792,5793],{"class":3774,"line":4005},[3772,5794,4020],{"class":3945},[3772,5796,5797],{"class":3774,"line":4011},[3772,5798,3965],{"emptyLinePlaceholder":3964},[3772,5800,5801,5803,5805,5808,5810,5813,5815,5817],{"class":3774,"line":4017},[3772,5802,3977],{"class":3941},[3772,5804,3981],{"class":3980},[3772,5806,5807],{"class":3778}," removeTrip",[3772,5809,5759],{"class":3945},[3772,5811,5812],{"class":3949},"id",[3772,5814,5765],{"class":3945},[3772,5816,5768],{"class":3980},[3772,5818,5771],{"class":3945},[3772,5820,5821,5823,5825],{"class":3774,"line":4023},[3772,5822,5776],{"class":3949},[3772,5824,5664],{"class":3984},[3772,5826,4806],{"class":3945},[3772,5828,5829,5831,5834],{"class":3774,"line":4028},[3772,5830,5785],{"class":3949},[3772,5832,5833],{"class":3949}," id",[3772,5835,4806],{"class":3945},[3772,5837,5838],{"class":3774,"line":4034},[3772,5839,4020],{"class":3945},[3762,5841,5844],{"className":3925,"code":5842,"filename":5843,"language":3927,"meta":3767,"style":3767},"\u002F\u002F reducers\u002FtripsReducer.ts\nimport { ADD_TRIP, REMOVE_TRIP, FETCH_TRIPS_START \u002F* ... *\u002F } from '..\u002Fconstants\u002FactionTypes'\n\nconst initialState = {\n    items: [],\n    loading: false,\n    error: null,\n}\n\nexport function tripsReducer(state = initialState, action) {\n    switch (action.type) {\n        case ADD_TRIP:\n            return {\n                ...state,\n                items: [...state.items, action.payload],\n            }\n        case REMOVE_TRIP:\n            return {\n                ...state,\n                items: state.items.filter((t) => t.id !== action.payload),\n            }\n        case FETCH_TRIPS_START:\n            return {\n                ...state,\n                loading: true,\n                error: null,\n            }\n        \u002F\u002F ... ще 5-10 кейсів\n        default:\n            return state\n    }\n}\n","3. Reducer",[3769,5845,5846,5851,5877,5881,5892,5899,5908,5918,5922,5926,5948,5963,5973,5980,5989,6012,6017,6025,6031,6039,6083,6087,6095,6101,6109,6119,6129,6134,6140,6148,6155,6160],{"__ignoreMap":3767},[3772,5847,5848],{"class":3774,"line":3775},[3772,5849,5850],{"class":3934},"\u002F\u002F reducers\u002FtripsReducer.ts\n",[3772,5852,5853,5855,5857,5859,5861,5863,5865,5868,5871,5873,5875],{"class":3774,"line":3938},[3772,5854,3942],{"class":3941},[3772,5856,3946],{"class":3945},[3772,5858,5731],{"class":3949},[3772,5860,3847],{"class":3945},[3772,5862,5736],{"class":3949},[3772,5864,3847],{"class":3945},[3772,5866,5867],{"class":3949},"FETCH_TRIPS_START",[3772,5869,5870],{"class":3934}," \u002F* ... *\u002F",[3772,5872,3952],{"class":3945},[3772,5874,3955],{"class":3941},[3772,5876,5743],{"class":3781},[3772,5878,5879],{"class":3774,"line":3961},[3772,5880,3965],{"emptyLinePlaceholder":3964},[3772,5882,5883,5886,5889],{"class":3774,"line":3968},[3772,5884,5885],{"class":3980},"const",[3772,5887,5888],{"class":3984}," initialState",[3772,5890,5891],{"class":3945}," = {\n",[3772,5893,5894,5896],{"class":3774,"line":3974},[3772,5895,5385],{"class":3949},[3772,5897,5898],{"class":3945}," [],\n",[3772,5900,5901,5904,5906],{"class":3774,"line":3996},[3772,5902,5903],{"class":3949},"    loading:",[3772,5905,4279],{"class":3980},[3772,5907,4806],{"class":3945},[3772,5909,5910,5913,5916],{"class":3774,"line":4005},[3772,5911,5912],{"class":3949},"    error:",[3772,5914,5915],{"class":3980}," null",[3772,5917,4806],{"class":3945},[3772,5919,5920],{"class":3774,"line":4011},[3772,5921,4316],{"class":3945},[3772,5923,5924],{"class":3774,"line":4017},[3772,5925,3965],{"emptyLinePlaceholder":3964},[3772,5927,5928,5930,5932,5934,5936,5938,5940,5942,5944,5946],{"class":3774,"line":4023},[3772,5929,3977],{"class":3941},[3772,5931,4199],{"class":3980},[3772,5933,5147],{"class":3778},[3772,5935,5150],{"class":3945},[3772,5937,5153],{"class":3949},[3772,5939,3988],{"class":3945},[3772,5941,5158],{"class":3949},[3772,5943,3847],{"class":3945},[3772,5945,5163],{"class":3949},[3772,5947,5166],{"class":3945},[3772,5949,5950,5953,5955,5957,5959,5961],{"class":3774,"line":4028},[3772,5951,5952],{"class":3941},"    switch",[3772,5954,5179],{"class":3945},[3772,5956,5163],{"class":3949},[3772,5958,4059],{"class":3945},[3772,5960,5048],{"class":3949},[3772,5962,5166],{"class":3945},[3772,5964,5965,5968,5970],{"class":3774,"line":4034},[3772,5966,5967],{"class":3941},"        case",[3772,5969,5650],{"class":3984},[3772,5971,5972],{"class":3945},":\n",[3772,5974,5975,5978],{"class":3774,"line":4068},[3772,5976,5977],{"class":3941},"            return",[3772,5979,4002],{"class":3945},[3772,5981,5982,5985,5987],{"class":3774,"line":4313},[3772,5983,5984],{"class":3945},"                ...",[3772,5986,5153],{"class":3949},[3772,5988,4806],{"class":3945},[3772,5990,5991,5994,5996,5998,6000,6002,6004,6006,6008,6010],{"class":3774,"line":4470},[3772,5992,5993],{"class":3949},"                items:",[3772,5995,5388],{"class":3945},[3772,5997,5153],{"class":3949},[3772,5999,4059],{"class":3945},[3772,6001,5237],{"class":3949},[3772,6003,3847],{"class":3945},[3772,6005,5163],{"class":3949},[3772,6007,4059],{"class":3945},[3772,6009,5059],{"class":3949},[3772,6011,5240],{"class":3945},[3772,6013,6014],{"class":3774,"line":4879},[3772,6015,6016],{"class":3945},"            }\n",[3772,6018,6019,6021,6023],{"class":3774,"line":4892},[3772,6020,5967],{"class":3941},[3772,6022,5664],{"class":3984},[3772,6024,5972],{"class":3945},[3772,6026,6027,6029],{"class":3774,"line":4903},[3772,6028,5977],{"class":3941},[3772,6030,4002],{"class":3945},[3772,6032,6033,6035,6037],{"class":3774,"line":4909},[3772,6034,5984],{"class":3945},[3772,6036,5153],{"class":3949},[3772,6038,4806],{"class":3945},[3772,6040,6041,6043,6045,6047,6049,6051,6054,6057,6060,6062,6064,6067,6069,6071,6074,6076,6078,6080],{"class":3774,"line":5521},[3772,6042,5993],{"class":3949},[3772,6044,5353],{"class":3949},[3772,6046,4059],{"class":3945},[3772,6048,5237],{"class":3949},[3772,6050,4059],{"class":3945},[3772,6052,6053],{"class":3778},"filter",[3772,6055,6056],{"class":3945},"((",[3772,6058,6059],{"class":3949},"t",[3772,6061,5765],{"class":3945},[3772,6063,5768],{"class":3980},[3772,6065,6066],{"class":3949}," t",[3772,6068,4059],{"class":3945},[3772,6070,5812],{"class":3949},[3772,6072,6073],{"class":3945}," !== ",[3772,6075,5163],{"class":3949},[3772,6077,4059],{"class":3945},[3772,6079,5059],{"class":3949},[3772,6081,6082],{"class":3945},"),\n",[3772,6084,6085],{"class":3774,"line":5527},[3772,6086,6016],{"class":3945},[3772,6088,6089,6091,6093],{"class":3774,"line":5533},[3772,6090,5967],{"class":3941},[3772,6092,5678],{"class":3984},[3772,6094,5972],{"class":3945},[3772,6096,6097,6099],{"class":3774,"line":5539},[3772,6098,5977],{"class":3941},[3772,6100,4002],{"class":3945},[3772,6102,6103,6105,6107],{"class":3774,"line":5545},[3772,6104,5984],{"class":3945},[3772,6106,5153],{"class":3949},[3772,6108,4806],{"class":3945},[3772,6110,6111,6114,6117],{"class":3774,"line":5550},[3772,6112,6113],{"class":3949},"                loading:",[3772,6115,6116],{"class":3980}," true",[3772,6118,4806],{"class":3945},[3772,6120,6122,6125,6127],{"class":3774,"line":6121},26,[3772,6123,6124],{"class":3949},"                error:",[3772,6126,5915],{"class":3980},[3772,6128,4806],{"class":3945},[3772,6130,6132],{"class":3774,"line":6131},27,[3772,6133,6016],{"class":3945},[3772,6135,6137],{"class":3774,"line":6136},28,[3772,6138,6139],{"class":3934},"        \u002F\u002F ... ще 5-10 кейсів\n",[3772,6141,6143,6146],{"class":3774,"line":6142},29,[3772,6144,6145],{"class":3941},"        default",[3772,6147,5972],{"class":3945},[3772,6149,6151,6153],{"class":3774,"line":6150},30,[3772,6152,5977],{"class":3941},[3772,6154,5265],{"class":3949},[3772,6156,6158],{"class":3774,"line":6157},31,[3772,6159,4906],{"class":3945},[3772,6161,6163],{"class":3774,"line":6162},32,[3772,6164,4316],{"class":3945},[3762,6166,6169],{"className":3925,"code":6167,"filename":6168,"language":3927,"meta":3767,"style":3767},"\u002F\u002F store\u002Findex.ts\nimport { createStore, applyMiddleware, combineReducers } from 'redux'\nimport thunk from 'redux-thunk'\nimport { composeWithDevTools } from 'redux-devtools-extension'\nimport { tripsReducer } from '.\u002Freducers\u002FtripsReducer'\n\nconst rootReducer = combineReducers({\n    trips: tripsReducer,\n})\n\nexport const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)))\n","4. Store",[3769,6170,6171,6176,6202,6215,6231,6247,6251,6264,6273,6277,6281],{"__ignoreMap":3767},[3772,6172,6173],{"class":3774,"line":3775},[3772,6174,6175],{"class":3934},"\u002F\u002F store\u002Findex.ts\n",[3772,6177,6178,6180,6182,6185,6187,6190,6192,6195,6197,6199],{"class":3774,"line":3938},[3772,6179,3942],{"class":3941},[3772,6181,3946],{"class":3945},[3772,6183,6184],{"class":3949},"createStore",[3772,6186,3847],{"class":3945},[3772,6188,6189],{"class":3949},"applyMiddleware",[3772,6191,3847],{"class":3945},[3772,6193,6194],{"class":3949},"combineReducers",[3772,6196,3952],{"class":3945},[3772,6198,3955],{"class":3941},[3772,6200,6201],{"class":3781}," 'redux'\n",[3772,6203,6204,6206,6209,6212],{"class":3774,"line":3961},[3772,6205,3942],{"class":3941},[3772,6207,6208],{"class":3949}," thunk",[3772,6210,6211],{"class":3941}," from",[3772,6213,6214],{"class":3781}," 'redux-thunk'\n",[3772,6216,6217,6219,6221,6224,6226,6228],{"class":3774,"line":3968},[3772,6218,3942],{"class":3941},[3772,6220,3946],{"class":3945},[3772,6222,6223],{"class":3949},"composeWithDevTools",[3772,6225,3952],{"class":3945},[3772,6227,3955],{"class":3941},[3772,6229,6230],{"class":3781}," 'redux-devtools-extension'\n",[3772,6232,6233,6235,6237,6240,6242,6244],{"class":3774,"line":3974},[3772,6234,3942],{"class":3941},[3772,6236,3946],{"class":3945},[3772,6238,6239],{"class":3949},"tripsReducer",[3772,6241,3952],{"class":3945},[3772,6243,3955],{"class":3941},[3772,6245,6246],{"class":3781}," '.\u002Freducers\u002FtripsReducer'\n",[3772,6248,6249],{"class":3774,"line":3996},[3772,6250,3965],{"emptyLinePlaceholder":3964},[3772,6252,6253,6255,6258,6260,6262],{"class":3774,"line":4005},[3772,6254,5885],{"class":3980},[3772,6256,6257],{"class":3984}," rootReducer",[3772,6259,3988],{"class":3945},[3772,6261,6194],{"class":3778},[3772,6263,3993],{"class":3945},[3772,6265,6266,6269,6271],{"class":3774,"line":4011},[3772,6267,6268],{"class":3949},"    trips:",[3772,6270,5147],{"class":3949},[3772,6272,4806],{"class":3945},[3772,6274,6275],{"class":3774,"line":4017},[3772,6276,4020],{"class":3945},[3772,6278,6279],{"class":3774,"line":4023},[3772,6280,3965],{"emptyLinePlaceholder":3964},[3772,6282,6283,6285,6287,6289,6291,6293,6295,6298,6300,6302,6304,6306,6308,6311],{"class":3774,"line":4028},[3772,6284,3977],{"class":3941},[3772,6286,3981],{"class":3980},[3772,6288,3985],{"class":3984},[3772,6290,3988],{"class":3945},[3772,6292,6184],{"class":3778},[3772,6294,5150],{"class":3945},[3772,6296,6297],{"class":3949},"rootReducer",[3772,6299,3847],{"class":3945},[3772,6301,6223],{"class":3778},[3772,6303,5150],{"class":3945},[3772,6305,6189],{"class":3778},[3772,6307,5150],{"class":3945},[3772,6309,6310],{"class":3949},"thunk",[3772,6312,6313],{"class":3945},")))\n",[3743,6315,6316,6319,6320,6323,6324,6327],{},[3829,6317,6318],{},"Підрахунок:"," Для однієї простої функції ми написали ",[3829,6321,6322],{},"4 файли"," та близько ",[3829,6325,6326],{},"80 рядків коду","!",[3747,6329,6331],{"id":6330},"рішення-redux-toolkit","Рішення: Redux Toolkit",[3743,6333,6334,6335,6338],{},"Redux Toolkit скорочує код у ",[3829,6336,6337],{},"5-10 разів"," та робить його читабельнішим:",[3762,6340,6342],{"className":3925,"code":6341,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FtripsSlice.ts\nimport { createSlice, PayloadAction } from '@reduxjs\u002Ftoolkit'\n\ninterface Trip {\n    id: string\n    title: string\n    region: string\n}\n\ninterface TripsState {\n    items: Trip[]\n    loading: boolean\n    error: string | null\n}\n\nconst initialState: TripsState = {\n    items: [],\n    loading: false,\n    error: null,\n}\n\n\u002F\u002F ВСЕ В ОДНОМУ МІСЦІ!\nexport const tripsSlice = createSlice({\n    name: 'trips',\n    initialState,\n    reducers: {\n        \u002F\u002F Додавання поїздки\n        addTrip(state, action: PayloadAction\u003CTrip>) {\n            \u002F\u002F Можемо мутувати state напряму! (Immer під капотом)\n            state.items.push(action.payload)\n        },\n        \u002F\u002F Видалення поїздки\n        removeTrip(state, action: PayloadAction\u003Cstring>) {\n            state.items = state.items.filter((t) => t.id !== action.payload)\n        },\n        \u002F\u002F Початок завантаження\n        setLoading(state, action: PayloadAction\u003Cboolean>) {\n            state.loading = action.payload\n        },\n    },\n})\n\n\u002F\u002F Експортуємо action creators (згенеровані автоматично!)\nexport const { addTrip, removeTrip, setLoading } = tripsSlice.actions\n\n\u002F\u002F Експортуємо reducer\nexport default tripsSlice.reducer\n",[3769,6343,6344,6349,6368,6372,6382,6392,6401,6410,6414,6418,6427,6440,6450,6465,6469,6473,6486,6492,6500,6508,6512,6516,6521,6536,6546,6553,6560,6565,6589,6594,6617,6622,6627,6651,6696,6701,6707,6732,6751,6756,6761,6766,6771,6777,6810,6815,6821],{"__ignoreMap":3767},[3772,6345,6346],{"class":3774,"line":3775},[3772,6347,6348],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fslices\u002FtripsSlice.ts\n",[3772,6350,6351,6353,6355,6357,6359,6362,6364,6366],{"class":3774,"line":3938},[3772,6352,3942],{"class":3941},[3772,6354,3946],{"class":3945},[3772,6356,3846],{"class":3949},[3772,6358,3847],{"class":3945},[3772,6360,6361],{"class":3949},"PayloadAction",[3772,6363,3952],{"class":3945},[3772,6365,3955],{"class":3941},[3772,6367,3958],{"class":3781},[3772,6369,6370],{"class":3774,"line":3961},[3772,6371,3965],{"emptyLinePlaceholder":3964},[3772,6373,6374,6377,6380],{"class":3774,"line":3968},[3772,6375,6376],{"class":3980},"interface",[3772,6378,6379],{"class":4042}," Trip",[3772,6381,4002],{"class":3945},[3772,6383,6384,6387,6389],{"class":3774,"line":3974},[3772,6385,6386],{"class":3949},"    id",[3772,6388,4800],{"class":3945},[3772,6390,6391],{"class":4042},"string\n",[3772,6393,6394,6397,6399],{"class":3774,"line":3996},[3772,6395,6396],{"class":3949},"    title",[3772,6398,4800],{"class":3945},[3772,6400,6391],{"class":4042},[3772,6402,6403,6406,6408],{"class":3774,"line":4005},[3772,6404,6405],{"class":3949},"    region",[3772,6407,4800],{"class":3945},[3772,6409,6391],{"class":4042},[3772,6411,6412],{"class":3774,"line":4011},[3772,6413,4316],{"class":3945},[3772,6415,6416],{"class":3774,"line":4017},[3772,6417,3965],{"emptyLinePlaceholder":3964},[3772,6419,6420,6422,6425],{"class":3774,"line":4023},[3772,6421,6376],{"class":3980},[3772,6423,6424],{"class":4042}," TripsState",[3772,6426,4002],{"class":3945},[3772,6428,6429,6432,6434,6437],{"class":3774,"line":4028},[3772,6430,6431],{"class":3949},"    items",[3772,6433,4800],{"class":3945},[3772,6435,6436],{"class":4042},"Trip",[3772,6438,6439],{"class":3945},"[]\n",[3772,6441,6442,6445,6447],{"class":3774,"line":4034},[3772,6443,6444],{"class":3949},"    loading",[3772,6446,4800],{"class":3945},[3772,6448,6449],{"class":4042},"boolean\n",[3772,6451,6452,6455,6457,6460,6463],{"class":3774,"line":4068},[3772,6453,6454],{"class":3949},"    error",[3772,6456,4800],{"class":3945},[3772,6458,6459],{"class":4042},"string",[3772,6461,6462],{"class":3945}," | ",[3772,6464,4816],{"class":4042},[3772,6466,6467],{"class":3774,"line":4313},[3772,6468,4316],{"class":3945},[3772,6470,6471],{"class":3774,"line":4470},[3772,6472,3965],{"emptyLinePlaceholder":3964},[3772,6474,6475,6477,6479,6481,6484],{"class":3774,"line":4879},[3772,6476,5885],{"class":3980},[3772,6478,5888],{"class":3984},[3772,6480,4800],{"class":3945},[3772,6482,6483],{"class":4042},"TripsState",[3772,6485,5891],{"class":3945},[3772,6487,6488,6490],{"class":3774,"line":4892},[3772,6489,5385],{"class":3949},[3772,6491,5898],{"class":3945},[3772,6493,6494,6496,6498],{"class":3774,"line":4903},[3772,6495,5903],{"class":3949},[3772,6497,4279],{"class":3980},[3772,6499,4806],{"class":3945},[3772,6501,6502,6504,6506],{"class":3774,"line":4909},[3772,6503,5912],{"class":3949},[3772,6505,5915],{"class":3980},[3772,6507,4806],{"class":3945},[3772,6509,6510],{"class":3774,"line":5521},[3772,6511,4316],{"class":3945},[3772,6513,6514],{"class":3774,"line":5527},[3772,6515,3965],{"emptyLinePlaceholder":3964},[3772,6517,6518],{"class":3774,"line":5533},[3772,6519,6520],{"class":3934},"\u002F\u002F ВСЕ В ОДНОМУ МІСЦІ!\n",[3772,6522,6523,6525,6527,6530,6532,6534],{"class":3774,"line":5539},[3772,6524,3977],{"class":3941},[3772,6526,3981],{"class":3980},[3772,6528,6529],{"class":3984}," tripsSlice",[3772,6531,3988],{"class":3945},[3772,6533,3846],{"class":3778},[3772,6535,3993],{"class":3945},[3772,6537,6538,6541,6544],{"class":3774,"line":5545},[3772,6539,6540],{"class":3949},"    name:",[3772,6542,6543],{"class":3781}," 'trips'",[3772,6545,4806],{"class":3945},[3772,6547,6548,6551],{"class":3774,"line":5550},[3772,6549,6550],{"class":3949},"    initialState",[3772,6552,4806],{"class":3945},[3772,6554,6555,6558],{"class":3774,"line":6121},[3772,6556,6557],{"class":3949},"    reducers:",[3772,6559,4002],{"class":3945},[3772,6561,6562],{"class":3774,"line":6131},[3772,6563,6564],{"class":3934},"        \u002F\u002F Додавання поїздки\n",[3772,6566,6567,6570,6572,6574,6576,6578,6580,6582,6584,6586],{"class":3774,"line":6136},[3772,6568,6569],{"class":3778},"        addTrip",[3772,6571,5150],{"class":3945},[3772,6573,5153],{"class":3949},[3772,6575,3847],{"class":3945},[3772,6577,5163],{"class":3949},[3772,6579,4800],{"class":3945},[3772,6581,6361],{"class":4042},[3772,6583,4051],{"class":3945},[3772,6585,6436],{"class":4042},[3772,6587,6588],{"class":3945},">) {\n",[3772,6590,6591],{"class":3774,"line":6142},[3772,6592,6593],{"class":3934},"            \u002F\u002F Можемо мутувати state напряму! (Immer під капотом)\n",[3772,6595,6596,6599,6601,6603,6605,6607,6609,6611,6613,6615],{"class":3774,"line":6150},[3772,6597,6598],{"class":3949},"            state",[3772,6600,4059],{"class":3945},[3772,6602,5237],{"class":3949},[3772,6604,4059],{"class":3945},[3772,6606,5337],{"class":3778},[3772,6608,5150],{"class":3945},[3772,6610,5163],{"class":3949},[3772,6612,4059],{"class":3945},[3772,6614,5059],{"class":3949},[3772,6616,5345],{"class":3945},[3772,6618,6619],{"class":3774,"line":6157},[3772,6620,6621],{"class":3945},"        },\n",[3772,6623,6624],{"class":3774,"line":6162},[3772,6625,6626],{"class":3934},"        \u002F\u002F Видалення поїздки\n",[3772,6628,6630,6633,6635,6637,6639,6641,6643,6645,6647,6649],{"class":3774,"line":6629},33,[3772,6631,6632],{"class":3778},"        removeTrip",[3772,6634,5150],{"class":3945},[3772,6636,5153],{"class":3949},[3772,6638,3847],{"class":3945},[3772,6640,5163],{"class":3949},[3772,6642,4800],{"class":3945},[3772,6644,6361],{"class":4042},[3772,6646,4051],{"class":3945},[3772,6648,6459],{"class":4042},[3772,6650,6588],{"class":3945},[3772,6652,6654,6656,6658,6660,6662,6664,6666,6668,6670,6672,6674,6676,6678,6680,6682,6684,6686,6688,6690,6692,6694],{"class":3774,"line":6653},34,[3772,6655,6598],{"class":3949},[3772,6657,4059],{"class":3945},[3772,6659,5237],{"class":3949},[3772,6661,3988],{"class":3945},[3772,6663,5153],{"class":3949},[3772,6665,4059],{"class":3945},[3772,6667,5237],{"class":3949},[3772,6669,4059],{"class":3945},[3772,6671,6053],{"class":3778},[3772,6673,6056],{"class":3945},[3772,6675,6059],{"class":3949},[3772,6677,5765],{"class":3945},[3772,6679,5768],{"class":3980},[3772,6681,6066],{"class":3949},[3772,6683,4059],{"class":3945},[3772,6685,5812],{"class":3949},[3772,6687,6073],{"class":3945},[3772,6689,5163],{"class":3949},[3772,6691,4059],{"class":3945},[3772,6693,5059],{"class":3949},[3772,6695,5345],{"class":3945},[3772,6697,6699],{"class":3774,"line":6698},35,[3772,6700,6621],{"class":3945},[3772,6702,6704],{"class":3774,"line":6703},36,[3772,6705,6706],{"class":3934},"        \u002F\u002F Початок завантаження\n",[3772,6708,6710,6713,6715,6717,6719,6721,6723,6725,6727,6730],{"class":3774,"line":6709},37,[3772,6711,6712],{"class":3778},"        setLoading",[3772,6714,5150],{"class":3945},[3772,6716,5153],{"class":3949},[3772,6718,3847],{"class":3945},[3772,6720,5163],{"class":3949},[3772,6722,4800],{"class":3945},[3772,6724,6361],{"class":4042},[3772,6726,4051],{"class":3945},[3772,6728,6729],{"class":4042},"boolean",[3772,6731,6588],{"class":3945},[3772,6733,6735,6737,6739,6742,6744,6746,6748],{"class":3774,"line":6734},38,[3772,6736,6598],{"class":3949},[3772,6738,4059],{"class":3945},[3772,6740,6741],{"class":3949},"loading",[3772,6743,3988],{"class":3945},[3772,6745,5163],{"class":3949},[3772,6747,4059],{"class":3945},[3772,6749,6750],{"class":3949},"payload\n",[3772,6752,6754],{"class":3774,"line":6753},39,[3772,6755,6621],{"class":3945},[3772,6757,6759],{"class":3774,"line":6758},40,[3772,6760,4014],{"class":3945},[3772,6762,6764],{"class":3774,"line":6763},41,[3772,6765,4020],{"class":3945},[3772,6767,6769],{"class":3774,"line":6768},42,[3772,6770,3965],{"emptyLinePlaceholder":3964},[3772,6772,6774],{"class":3774,"line":6773},43,[3772,6775,6776],{"class":3934},"\u002F\u002F Експортуємо action creators (згенеровані автоматично!)\n",[3772,6778,6780,6782,6784,6786,6789,6791,6794,6796,6799,6802,6805,6807],{"class":3774,"line":6779},44,[3772,6781,3977],{"class":3941},[3772,6783,3981],{"class":3980},[3772,6785,3946],{"class":3945},[3772,6787,6788],{"class":3984},"addTrip",[3772,6790,3847],{"class":3945},[3772,6792,6793],{"class":3984},"removeTrip",[3772,6795,3847],{"class":3945},[3772,6797,6798],{"class":3984},"setLoading",[3772,6800,6801],{"class":3945}," } = ",[3772,6803,6804],{"class":3949},"tripsSlice",[3772,6806,4059],{"class":3945},[3772,6808,6809],{"class":3949},"actions\n",[3772,6811,6813],{"class":3774,"line":6812},45,[3772,6814,3965],{"emptyLinePlaceholder":3964},[3772,6816,6818],{"class":3774,"line":6817},46,[3772,6819,6820],{"class":3934},"\u002F\u002F Експортуємо reducer\n",[3772,6822,6824,6826,6828,6830,6832],{"class":3774,"line":6823},47,[3772,6825,3977],{"class":3941},[3772,6827,4196],{"class":3941},[3772,6829,6529],{"class":3949},[3772,6831,4059],{"class":3945},[3772,6833,6834],{"class":3949},"reducer\n",[3743,6836,6837],{},[3829,6838,6839],{},"Що ми отримали:",[3833,6841,6842,6849,6856,6863,6869],{},[3836,6843,6844,6845,6848],{},"✅ Весь код в ",[3829,6846,6847],{},"одному файлі"," замість чотирьох",[3836,6850,6851,6852,6855],{},"✅ ",[3829,6853,6854],{},"Автоматична генерація"," action creators",[3836,6857,6858,6859,6862],{},"✅ Можемо ",[3829,6860,6861],{},"мутувати стан"," напряму (Immer робить його іммутабельним)",[3836,6864,6851,6865,6868],{},[3829,6866,6867],{},"TypeScript підтримка"," з коробки",[3836,6870,6871],{},"✅ Менше коду — менше помилок",[5075,6873,6874,6879,6882,6910],{},[3743,6875,6876],{},[3829,6877,6878],{},"Redux Toolkit = \"Batteries Included\"",[3743,6880,6881],{},"Redux Toolkit включає все необхідне з коробки:",[3833,6883,6884,6890,6895,6901,6907],{},[3836,6885,6851,6886,6889],{},[3769,6887,6888],{},"redux"," — базова бібліотека",[3836,6891,6851,6892,6894],{},[3769,6893,4105],{}," — для асинхронних дій",[3836,6896,6851,6897,6900],{},[3769,6898,6899],{},"immer"," — для безпечних \"мутацій\"",[3836,6902,6851,6903,6906],{},[3769,6904,6905],{},"reselect"," — для мемоїзації селекторів",[3836,6908,6909],{},"✅ Redux DevTools — для дебагу",[3743,6911,6912],{},"Не потрібно встановлювати окремо!",[4495,6914],{},[3738,6916,6918],{"id":6917},"ключові-концепції-redux-toolkit-та-як-вони-працюють","Ключові концепції Redux Toolkit та як вони працюють",[3743,6920,6921],{},"Розглянемо кожну абстракцію RTK на глибокому рівні з детальними прикладами коду.",[3747,6923,6925],{"id":6924},"_1-action-дія-та-action-creator-творець-дії","1. Action (Дія) та Action Creator (Творець дії)",[3743,6927,6928,6930,6931,4094],{},[3829,6929,4604],{}," — це звичайний JavaScript-об'єкт, який повідомляє сховищу про те, що в застосунку відбулася певна подія. У сучасному Redux усі дії відповідають специфікації ",[3829,6932,6933],{},"Flux Standard Action (FSA)",[3762,6935,6937],{"className":3925,"code":6936,"language":3927,"meta":3767,"style":3767},"interface FluxStandardAction\u003CPayload = any, Meta = any> {\n    type: string \u002F\u002F Обов'язковий унікальний ідентифікатор події\n    payload?: Payload \u002F\u002F Дані дії (корисне навантаження)\n    error?: boolean \u002F\u002F Прапорець, що вказує на наявність помилки в payload\n    meta?: Meta \u002F\u002F Додаткові метадані (наприклад, analyticsId, timestamp)\n}\n",[3769,6938,6939,6968,6979,6991,7002,7014],{"__ignoreMap":3767},[3772,6940,6941,6943,6946,6948,6951,6953,6956,6958,6961,6963,6965],{"class":3774,"line":3775},[3772,6942,6376],{"class":3980},[3772,6944,6945],{"class":4042}," FluxStandardAction",[3772,6947,4051],{"class":3945},[3772,6949,6950],{"class":4042},"Payload",[3772,6952,3988],{"class":3945},[3772,6954,6955],{"class":4042},"any",[3772,6957,3847],{"class":3945},[3772,6959,6960],{"class":4042},"Meta",[3772,6962,3988],{"class":3945},[3772,6964,6955],{"class":4042},[3772,6966,6967],{"class":3945},"> {\n",[3772,6969,6970,6972,6974,6976],{"class":3774,"line":3938},[3772,6971,4970],{"class":3949},[3772,6973,4800],{"class":3945},[3772,6975,6459],{"class":4042},[3772,6977,6978],{"class":3934}," \u002F\u002F Обов'язковий унікальний ідентифікатор події\n",[3772,6980,6981,6983,6986,6988],{"class":3774,"line":3961},[3772,6982,4986],{"class":3949},[3772,6984,6985],{"class":3945},"?: ",[3772,6987,6950],{"class":4042},[3772,6989,6990],{"class":3934}," \u002F\u002F Дані дії (корисне навантаження)\n",[3772,6992,6993,6995,6997,6999],{"class":3774,"line":3968},[3772,6994,6454],{"class":3949},[3772,6996,6985],{"class":3945},[3772,6998,6729],{"class":4042},[3772,7000,7001],{"class":3934}," \u002F\u002F Прапорець, що вказує на наявність помилки в payload\n",[3772,7003,7004,7007,7009,7011],{"class":3774,"line":3974},[3772,7005,7006],{"class":3949},"    meta",[3772,7008,6985],{"class":3945},[3772,7010,6960],{"class":4042},[3772,7012,7013],{"class":3934}," \u002F\u002F Додаткові метадані (наприклад, analyticsId, timestamp)\n",[3772,7015,7016],{"class":3774,"line":3996},[3772,7017,4316],{"class":3945},[3743,7019,7020,7023],{},[3829,7021,7022],{},"Action Creator"," — це функція, яка інкапсулює створення та валідацію об'єкта дії.",[7025,7026,7028,7029],"h4",{"id":7027},"ручне-створення-дії-через-createaction","Ручне створення дії через ",[3769,7030,7031],{},"createAction",[3743,7033,7034,7035,7037,7038,7040],{},"Хоча зазвичай дії генеруються автоматично всередині ",[3769,7036,3846],{},", утиліта ",[3769,7039,7031],{}," дозволяє створювати автономні дії:",[3762,7042,7044],{"className":3925,"code":7043,"language":3927,"meta":3767,"style":3767},"import { createAction, nanoid } from '@reduxjs\u002Ftoolkit'\n\n\u002F\u002F Базовий Action Creator:\nexport const resetAllFilters = createAction('filters\u002Freset')\n\u002F\u002F Виклик resetAllFilters() повертає { type: 'filters\u002Freset' }\n\n\u002F\u002F Action Creator з функцією підготовки (Prepare Callback):\nexport const addCustomTrip = createAction('trips\u002FaddCustom', (title: string, region: string) => {\n    return {\n        payload: {\n            id: nanoid(), \u002F\u002F Генерація унікального ID\n            title,\n            region,\n            createdAt: new Date().toISOString(), \u002F\u002F Серіалізована дата!\n        },\n        meta: {\n            analyticsEvent: 'TRIP_CREATED_MANUALLY',\n        },\n    }\n})\n\n\u002F\u002F Використання:\nconst action = addCustomTrip('Карпати', 'Захід')\nconsole.log(action)\n\u002F\u002F {\n\u002F\u002F   type: 'trips\u002FaddCustom',\n\u002F\u002F   payload: { id: 'V1StGXR8_Z5jdHi6B-myT', title: 'Карпати', region: 'Захід', createdAt: '...' },\n\u002F\u002F   meta: { analyticsEvent: 'TRIP_CREATED_MANUALLY' }\n\u002F\u002F }\n",[3769,7045,7046,7065,7069,7074,7094,7099,7103,7108,7151,7157,7164,7178,7185,7192,7214,7218,7225,7235,7239,7243,7247,7251,7256,7280,7296,7301,7306,7311,7316],{"__ignoreMap":3767},[3772,7047,7048,7050,7052,7054,7056,7059,7061,7063],{"class":3774,"line":3775},[3772,7049,3942],{"class":3941},[3772,7051,3946],{"class":3945},[3772,7053,7031],{"class":3949},[3772,7055,3847],{"class":3945},[3772,7057,7058],{"class":3949},"nanoid",[3772,7060,3952],{"class":3945},[3772,7062,3955],{"class":3941},[3772,7064,3958],{"class":3781},[3772,7066,7067],{"class":3774,"line":3938},[3772,7068,3965],{"emptyLinePlaceholder":3964},[3772,7070,7071],{"class":3774,"line":3961},[3772,7072,7073],{"class":3934},"\u002F\u002F Базовий Action Creator:\n",[3772,7075,7076,7078,7080,7083,7085,7087,7089,7092],{"class":3774,"line":3968},[3772,7077,3977],{"class":3941},[3772,7079,3981],{"class":3980},[3772,7081,7082],{"class":3984}," resetAllFilters",[3772,7084,3988],{"class":3945},[3772,7086,7031],{"class":3778},[3772,7088,5150],{"class":3945},[3772,7090,7091],{"class":3781},"'filters\u002Freset'",[3772,7093,5345],{"class":3945},[3772,7095,7096],{"class":3774,"line":3974},[3772,7097,7098],{"class":3934},"\u002F\u002F Виклик resetAllFilters() повертає { type: 'filters\u002Freset' }\n",[3772,7100,7101],{"class":3774,"line":3996},[3772,7102,3965],{"emptyLinePlaceholder":3964},[3772,7104,7105],{"class":3774,"line":4005},[3772,7106,7107],{"class":3934},"\u002F\u002F Action Creator з функцією підготовки (Prepare Callback):\n",[3772,7109,7110,7112,7114,7117,7119,7121,7123,7126,7129,7132,7134,7136,7138,7141,7143,7145,7147,7149],{"class":3774,"line":4011},[3772,7111,3977],{"class":3941},[3772,7113,3981],{"class":3980},[3772,7115,7116],{"class":3984}," addCustomTrip",[3772,7118,3988],{"class":3945},[3772,7120,7031],{"class":3778},[3772,7122,5150],{"class":3945},[3772,7124,7125],{"class":3781},"'trips\u002FaddCustom'",[3772,7127,7128],{"class":3945},", (",[3772,7130,7131],{"class":3949},"title",[3772,7133,4800],{"class":3945},[3772,7135,6459],{"class":4042},[3772,7137,3847],{"class":3945},[3772,7139,7140],{"class":3949},"region",[3772,7142,4800],{"class":3945},[3772,7144,6459],{"class":4042},[3772,7146,5765],{"class":3945},[3772,7148,5768],{"class":3980},[3772,7150,4002],{"class":3945},[3772,7152,7153,7155],{"class":3774,"line":4017},[3772,7154,4210],{"class":3941},[3772,7156,4002],{"class":3945},[3772,7158,7159,7162],{"class":3774,"line":4023},[3772,7160,7161],{"class":3949},"        payload:",[3772,7163,4002],{"class":3945},[3772,7165,7166,7169,7172,7175],{"class":3774,"line":4028},[3772,7167,7168],{"class":3949},"            id:",[3772,7170,7171],{"class":3778}," nanoid",[3772,7173,7174],{"class":3945},"(), ",[3772,7176,7177],{"class":3934},"\u002F\u002F Генерація унікального ID\n",[3772,7179,7180,7183],{"class":3774,"line":4034},[3772,7181,7182],{"class":3949},"            title",[3772,7184,4806],{"class":3945},[3772,7186,7187,7190],{"class":3774,"line":4068},[3772,7188,7189],{"class":3949},"            region",[3772,7191,4806],{"class":3945},[3772,7193,7194,7197,7200,7203,7206,7209,7211],{"class":3774,"line":4313},[3772,7195,7196],{"class":3949},"            createdAt:",[3772,7198,7199],{"class":3980}," new",[3772,7201,7202],{"class":3778}," Date",[3772,7204,7205],{"class":3945},"().",[3772,7207,7208],{"class":3778},"toISOString",[3772,7210,7174],{"class":3945},[3772,7212,7213],{"class":3934},"\u002F\u002F Серіалізована дата!\n",[3772,7215,7216],{"class":3774,"line":4470},[3772,7217,6621],{"class":3945},[3772,7219,7220,7223],{"class":3774,"line":4879},[3772,7221,7222],{"class":3949},"        meta:",[3772,7224,4002],{"class":3945},[3772,7226,7227,7230,7233],{"class":3774,"line":4892},[3772,7228,7229],{"class":3949},"            analyticsEvent:",[3772,7231,7232],{"class":3781}," 'TRIP_CREATED_MANUALLY'",[3772,7234,4806],{"class":3945},[3772,7236,7237],{"class":3774,"line":4903},[3772,7238,6621],{"class":3945},[3772,7240,7241],{"class":3774,"line":4909},[3772,7242,4906],{"class":3945},[3772,7244,7245],{"class":3774,"line":5521},[3772,7246,4020],{"class":3945},[3772,7248,7249],{"class":3774,"line":5527},[3772,7250,3965],{"emptyLinePlaceholder":3964},[3772,7252,7253],{"class":3774,"line":5533},[3772,7254,7255],{"class":3934},"\u002F\u002F Використання:\n",[3772,7257,7258,7260,7263,7265,7268,7270,7273,7275,7278],{"class":3774,"line":5539},[3772,7259,5885],{"class":3980},[3772,7261,7262],{"class":3984}," action",[3772,7264,3988],{"class":3945},[3772,7266,7267],{"class":3778},"addCustomTrip",[3772,7269,5150],{"class":3945},[3772,7271,7272],{"class":3781},"'Карпати'",[3772,7274,3847],{"class":3945},[3772,7276,7277],{"class":3781},"'Захід'",[3772,7279,5345],{"class":3945},[3772,7281,7282,7285,7287,7290,7292,7294],{"class":3774,"line":5545},[3772,7283,7284],{"class":3949},"console",[3772,7286,4059],{"class":3945},[3772,7288,7289],{"class":3778},"log",[3772,7291,5150],{"class":3945},[3772,7293,5163],{"class":3949},[3772,7295,5345],{"class":3945},[3772,7297,7298],{"class":3774,"line":5550},[3772,7299,7300],{"class":3934},"\u002F\u002F {\n",[3772,7302,7303],{"class":3774,"line":6121},[3772,7304,7305],{"class":3934},"\u002F\u002F   type: 'trips\u002FaddCustom',\n",[3772,7307,7308],{"class":3774,"line":6131},[3772,7309,7310],{"class":3934},"\u002F\u002F   payload: { id: 'V1StGXR8_Z5jdHi6B-myT', title: 'Карпати', region: 'Захід', createdAt: '...' },\n",[3772,7312,7313],{"class":3774,"line":6136},[3772,7314,7315],{"class":3934},"\u002F\u002F   meta: { analyticsEvent: 'TRIP_CREATED_MANUALLY' }\n",[3772,7317,7318],{"class":3774,"line":6142},[3772,7319,7320],{"class":3934},"\u002F\u002F }\n",[7025,7322,7324,7325,4669],{"id":7323},"механізм-зіставлення-дій-actionmatch","Механізм зіставлення дій (",[3769,7326,7327],{},"action.match",[3743,7329,7330,7331,4094],{},"Action Creators, створені в RTK, мають вбудований предикатний метод ",[3769,7332,7333],{},"match(action)",[3762,7335,7337],{"className":3925,"code":7336,"language":3927,"meta":3767,"style":3767},"const action: unknown = { type: 'filters\u002Freset' }\n\nif (resetAllFilters.match(action)) {\n    \u002F\u002F TypeScript автоматично звужує тип action до PayloadAction\n    console.log('Це дійсно дія скидання фільтрів!')\n}\n",[3769,7338,7339,7361,7365,7387,7392,7408],{"__ignoreMap":3767},[3772,7340,7341,7343,7345,7347,7350,7353,7356,7359],{"class":3774,"line":3775},[3772,7342,5885],{"class":3980},[3772,7344,7262],{"class":3984},[3772,7346,4800],{"class":3945},[3772,7348,7349],{"class":4042},"unknown",[3772,7351,7352],{"class":3945}," = { ",[3772,7354,7355],{"class":3949},"type:",[3772,7357,7358],{"class":3781}," 'filters\u002Freset'",[3772,7360,4787],{"class":3945},[3772,7362,7363],{"class":3774,"line":3938},[3772,7364,3965],{"emptyLinePlaceholder":3964},[3772,7366,7367,7370,7372,7375,7377,7380,7382,7384],{"class":3774,"line":3961},[3772,7368,7369],{"class":3941},"if",[3772,7371,5179],{"class":3945},[3772,7373,7374],{"class":3949},"resetAllFilters",[3772,7376,4059],{"class":3945},[3772,7378,7379],{"class":3778},"match",[3772,7381,5150],{"class":3945},[3772,7383,5163],{"class":3949},[3772,7385,7386],{"class":3945},")) {\n",[3772,7388,7389],{"class":3774,"line":3968},[3772,7390,7391],{"class":3934},"    \u002F\u002F TypeScript автоматично звужує тип action до PayloadAction\n",[3772,7393,7394,7397,7399,7401,7403,7406],{"class":3774,"line":3974},[3772,7395,7396],{"class":3949},"    console",[3772,7398,4059],{"class":3945},[3772,7400,7289],{"class":3778},[3772,7402,5150],{"class":3945},[3772,7404,7405],{"class":3781},"'Це дійсно дія скидання фільтрів!'",[3772,7407,5345],{"class":3945},[3772,7409,7410],{"class":3774,"line":3996},[3772,7411,4316],{"class":3945},[4495,7413],{},[3747,7415,7417],{"id":7416},"_2-reducer-редуктор-та-механіка-immer-під-капотом","2. Reducer (Редуктор) та механіка Immer під капотом",[3743,7419,7420,7422],{},[3829,7421,5117],{}," — це чиста функція для оновлення стану:",[7424,7425,7426],"math-formula",{},"f: (\\text{PreviousState}, \\text{Action}) \\longrightarrow \\text{NewState}",[7025,7428,7430],{"id":7429},"чому-редуктор-зобовязаний-бути-чистою-функцією","Чому редуктор зобов'язаний бути чистою функцією?",[3743,7432,7433,7434,4094],{},"У редукторі ",[3829,7435,7436],{},"категорично заборонено",[4588,7438,7439,7446,7461],{},[3836,7440,7441,7442,7445],{},"Виконувати асинхронні виклики (HTTP-запити, таймери ",[3769,7443,7444],{},"setTimeout",");",[3836,7447,7448,7449,3847,7452,3847,7455,3847,7458,7445],{},"Генерувати недетерміновані значення (",[3769,7450,7451],{},"Math.random()",[3769,7453,7454],{},"nanoid()",[3769,7456,7457],{},"new Date()",[3769,7459,7460],{},"Date.now()",[3836,7462,7463,7464,7467],{},"Змінювати глобальні змінні або викликати побічні ефекти (",[4508,7465,7466],{},"Side Effects",").",[3743,7469,7470],{},"Якщо для однакового стану та однакової дії редуктор повертатиме різні результати, передбачуваність стану Redux руйнується, а Time-Travel Debugging стає неможливим.",[7025,7472,7474],{"id":7473},"як-immer-забезпечує-безпеку-мутуючого-синтаксису","Як Immer забезпечує безпеку мутуючого синтаксису",[3743,7476,7477],{},"У класичному Redux оновлення вкладеного поля вимагало жахливого «spread hell»:",[3762,7479,7481],{"className":3925,"code":7480,"language":3927,"meta":3767,"style":3767},"\u002F\u002F СТАРИЙ ПІДХІД (Legacy Redux): Складно читати, легко зробити помилку!\nfunction legacyReducer(state = initialState, action) {\n    switch (action.type) {\n        case 'trips\u002FupdatePlaceRating':\n            return {\n                ...state,\n                trips: state.trips.map((trip) => {\n                    if (trip.id !== action.payload.tripId) return trip\n                    return {\n                        ...trip,\n                        places: trip.places.map((place) => {\n                            if (place.id !== action.payload.placeId) return place\n                            return {\n                                ...place,\n                                rating: action.payload.rating,\n                            }\n                        }),\n                    }\n                }),\n            }\n        default:\n            return state\n    }\n}\n",[3769,7482,7483,7488,7509,7523,7532,7538,7546,7573,7606,7613,7622,7649,7682,7689,7698,7716,7721,7726,7731,7736,7740,7746,7752,7756],{"__ignoreMap":3767},[3772,7484,7485],{"class":3774,"line":3775},[3772,7486,7487],{"class":3934},"\u002F\u002F СТАРИЙ ПІДХІД (Legacy Redux): Складно читати, легко зробити помилку!\n",[3772,7489,7490,7492,7495,7497,7499,7501,7503,7505,7507],{"class":3774,"line":3938},[3772,7491,5144],{"class":3980},[3772,7493,7494],{"class":3778}," legacyReducer",[3772,7496,5150],{"class":3945},[3772,7498,5153],{"class":3949},[3772,7500,3988],{"class":3945},[3772,7502,5158],{"class":3949},[3772,7504,3847],{"class":3945},[3772,7506,5163],{"class":3949},[3772,7508,5166],{"class":3945},[3772,7510,7511,7513,7515,7517,7519,7521],{"class":3774,"line":3961},[3772,7512,5952],{"class":3941},[3772,7514,5179],{"class":3945},[3772,7516,5163],{"class":3949},[3772,7518,4059],{"class":3945},[3772,7520,5048],{"class":3949},[3772,7522,5166],{"class":3945},[3772,7524,7525,7527,7530],{"class":3774,"line":3968},[3772,7526,5967],{"class":3941},[3772,7528,7529],{"class":3781}," 'trips\u002FupdatePlaceRating'",[3772,7531,5972],{"class":3945},[3772,7533,7534,7536],{"class":3774,"line":3974},[3772,7535,5977],{"class":3941},[3772,7537,4002],{"class":3945},[3772,7539,7540,7542,7544],{"class":3774,"line":3996},[3772,7541,5984],{"class":3945},[3772,7543,5153],{"class":3949},[3772,7545,4806],{"class":3945},[3772,7547,7548,7551,7553,7555,7558,7560,7563,7565,7567,7569,7571],{"class":3774,"line":4005},[3772,7549,7550],{"class":3949},"                trips:",[3772,7552,5353],{"class":3949},[3772,7554,4059],{"class":3945},[3772,7556,7557],{"class":3949},"trips",[3772,7559,4059],{"class":3945},[3772,7561,7562],{"class":3778},"map",[3772,7564,6056],{"class":3945},[3772,7566,5762],{"class":3949},[3772,7568,5765],{"class":3945},[3772,7570,5768],{"class":3980},[3772,7572,4002],{"class":3945},[3772,7574,7575,7578,7580,7582,7584,7586,7588,7590,7592,7594,7596,7599,7601,7603],{"class":3774,"line":4011},[3772,7576,7577],{"class":3941},"                    if",[3772,7579,5179],{"class":3945},[3772,7581,5762],{"class":3949},[3772,7583,4059],{"class":3945},[3772,7585,5812],{"class":3949},[3772,7587,6073],{"class":3945},[3772,7589,5163],{"class":3949},[3772,7591,4059],{"class":3945},[3772,7593,5059],{"class":3949},[3772,7595,4059],{"class":3945},[3772,7597,7598],{"class":3949},"tripId",[3772,7600,5765],{"class":3945},[3772,7602,5350],{"class":3941},[3772,7604,7605],{"class":3949}," trip\n",[3772,7607,7608,7611],{"class":3774,"line":4017},[3772,7609,7610],{"class":3941},"                    return",[3772,7612,4002],{"class":3945},[3772,7614,7615,7618,7620],{"class":3774,"line":4023},[3772,7616,7617],{"class":3945},"                        ...",[3772,7619,5762],{"class":3949},[3772,7621,4806],{"class":3945},[3772,7623,7624,7627,7629,7631,7634,7636,7638,7640,7643,7645,7647],{"class":3774,"line":4028},[3772,7625,7626],{"class":3949},"                        places:",[3772,7628,5788],{"class":3949},[3772,7630,4059],{"class":3945},[3772,7632,7633],{"class":3949},"places",[3772,7635,4059],{"class":3945},[3772,7637,7562],{"class":3778},[3772,7639,6056],{"class":3945},[3772,7641,7642],{"class":3949},"place",[3772,7644,5765],{"class":3945},[3772,7646,5768],{"class":3980},[3772,7648,4002],{"class":3945},[3772,7650,7651,7654,7656,7658,7660,7662,7664,7666,7668,7670,7672,7675,7677,7679],{"class":3774,"line":4034},[3772,7652,7653],{"class":3941},"                            if",[3772,7655,5179],{"class":3945},[3772,7657,7642],{"class":3949},[3772,7659,4059],{"class":3945},[3772,7661,5812],{"class":3949},[3772,7663,6073],{"class":3945},[3772,7665,5163],{"class":3949},[3772,7667,4059],{"class":3945},[3772,7669,5059],{"class":3949},[3772,7671,4059],{"class":3945},[3772,7673,7674],{"class":3949},"placeId",[3772,7676,5765],{"class":3945},[3772,7678,5350],{"class":3941},[3772,7680,7681],{"class":3949}," place\n",[3772,7683,7684,7687],{"class":3774,"line":4068},[3772,7685,7686],{"class":3941},"                            return",[3772,7688,4002],{"class":3945},[3772,7690,7691,7694,7696],{"class":3774,"line":4313},[3772,7692,7693],{"class":3945},"                                ...",[3772,7695,7642],{"class":3949},[3772,7697,4806],{"class":3945},[3772,7699,7700,7703,7705,7707,7709,7711,7714],{"class":3774,"line":4470},[3772,7701,7702],{"class":3949},"                                rating:",[3772,7704,7262],{"class":3949},[3772,7706,4059],{"class":3945},[3772,7708,5059],{"class":3949},[3772,7710,4059],{"class":3945},[3772,7712,7713],{"class":3949},"rating",[3772,7715,4806],{"class":3945},[3772,7717,7718],{"class":3774,"line":4879},[3772,7719,7720],{"class":3945},"                            }\n",[3772,7722,7723],{"class":3774,"line":4892},[3772,7724,7725],{"class":3945},"                        }),\n",[3772,7727,7728],{"class":3774,"line":4903},[3772,7729,7730],{"class":3945},"                    }\n",[3772,7732,7733],{"class":3774,"line":4909},[3772,7734,7735],{"class":3945},"                }),\n",[3772,7737,7738],{"class":3774,"line":5521},[3772,7739,6016],{"class":3945},[3772,7741,7742,7744],{"class":3774,"line":5527},[3772,7743,6145],{"class":3941},[3772,7745,5972],{"class":3945},[3772,7747,7748,7750],{"class":3774,"line":5533},[3772,7749,5977],{"class":3941},[3772,7751,5265],{"class":3949},[3772,7753,7754],{"class":3774,"line":5539},[3772,7755,4906],{"class":3945},[3772,7757,7758],{"class":3774,"line":5545},[3772,7759,4316],{"class":3945},[3743,7761,7762,7763,7765,7766,7769,7770,7775,7776,7779],{},"У Redux Toolkit всі редуктори всередині ",[3769,7764,3846],{}," використовують бібліотеку ",[3829,7767,7768],{},"Immer",". Immer огортає стан у нативний JavaScript-об'єкт ",[3829,7771,7772],{},[3769,7773,7774],{},"Proxy"," (механіка ",[4508,7777,7778],{},"Copy-on-Write","):",[3762,7781,7783],{"className":3925,"code":7782,"language":3927,"meta":3767,"style":3767},"\u002F\u002F СУЧАСНИЙ ПІДХІД (Redux Toolkit + Immer):\nupdatePlaceRating(state, action: PayloadAction\u003C{ tripId: string; placeId: string; rating: number }>) {\n  const trip = state.trips.find(t => t.id === action.payload.tripId);\n  const place = trip?.places.find(p => p.id === action.payload.placeId);\n  if (place) {\n    place.rating = action.payload.rating; \u002F\u002F Пряма мутація draft-об'єкта!\n  }\n}\n",[3769,7784,7785,7790,7837,7885,7932,7943,7969,7974],{"__ignoreMap":3767},[3772,7786,7787],{"class":3774,"line":3775},[3772,7788,7789],{"class":3934},"\u002F\u002F СУЧАСНИЙ ПІДХІД (Redux Toolkit + Immer):\n",[3772,7791,7792,7795,7797,7799,7801,7803,7805,7807,7810,7813,7816,7819,7821,7823,7825,7827,7829,7831,7834],{"class":3774,"line":3938},[3772,7793,7794],{"class":3778},"updatePlaceRating",[3772,7796,5150],{"class":3945},[3772,7798,5153],{"class":3949},[3772,7800,3847],{"class":3945},[3772,7802,5163],{"class":3949},[3772,7804,4800],{"class":3945},[3772,7806,6361],{"class":3949},[3772,7808,7809],{"class":3945},"\u003C{ ",[3772,7811,7812],{"class":3949},"tripId:",[3772,7814,7815],{"class":3949}," string",[3772,7817,7818],{"class":3945},"; ",[3772,7820,7674],{"class":3949},[3772,7822,4800],{"class":3945},[3772,7824,6459],{"class":3949},[3772,7826,7818],{"class":3945},[3772,7828,7713],{"class":3949},[3772,7830,4800],{"class":3945},[3772,7832,7833],{"class":3949},"number",[3772,7835,7836],{"class":3945}," }>) {\n",[3772,7838,7839,7842,7844,7846,7848,7850,7852,7854,7857,7859,7861,7864,7866,7868,7870,7872,7874,7876,7878,7880,7882],{"class":3774,"line":3961},[3772,7840,7841],{"class":3980},"  const",[3772,7843,5788],{"class":3984},[3772,7845,3988],{"class":3945},[3772,7847,5153],{"class":3949},[3772,7849,4059],{"class":3945},[3772,7851,7557],{"class":3949},[3772,7853,4059],{"class":3945},[3772,7855,7856],{"class":3778},"find",[3772,7858,5150],{"class":3945},[3772,7860,6059],{"class":3949},[3772,7862,7863],{"class":3980}," =>",[3772,7865,6066],{"class":3949},[3772,7867,4059],{"class":3945},[3772,7869,5812],{"class":3949},[3772,7871,5188],{"class":3945},[3772,7873,5163],{"class":3949},[3772,7875,4059],{"class":3945},[3772,7877,5059],{"class":3949},[3772,7879,4059],{"class":3945},[3772,7881,7598],{"class":3949},[3772,7883,7884],{"class":3945},");\n",[3772,7886,7887,7889,7892,7894,7896,7899,7901,7903,7905,7907,7909,7911,7914,7916,7918,7920,7922,7924,7926,7928,7930],{"class":3774,"line":3968},[3772,7888,7841],{"class":3980},[3772,7890,7891],{"class":3984}," place",[3772,7893,3988],{"class":3945},[3772,7895,5762],{"class":3949},[3772,7897,7898],{"class":3945},"?.",[3772,7900,7633],{"class":3949},[3772,7902,4059],{"class":3945},[3772,7904,7856],{"class":3778},[3772,7906,5150],{"class":3945},[3772,7908,3743],{"class":3949},[3772,7910,7863],{"class":3980},[3772,7912,7913],{"class":3949}," p",[3772,7915,4059],{"class":3945},[3772,7917,5812],{"class":3949},[3772,7919,5188],{"class":3945},[3772,7921,5163],{"class":3949},[3772,7923,4059],{"class":3945},[3772,7925,5059],{"class":3949},[3772,7927,4059],{"class":3945},[3772,7929,7674],{"class":3949},[3772,7931,7884],{"class":3945},[3772,7933,7934,7937,7939,7941],{"class":3774,"line":3974},[3772,7935,7936],{"class":3941},"  if",[3772,7938,5179],{"class":3945},[3772,7940,7642],{"class":3949},[3772,7942,5166],{"class":3945},[3772,7944,7945,7948,7950,7952,7954,7956,7958,7960,7962,7964,7966],{"class":3774,"line":3996},[3772,7946,7947],{"class":3949},"    place",[3772,7949,4059],{"class":3945},[3772,7951,7713],{"class":3949},[3772,7953,3988],{"class":3945},[3772,7955,5163],{"class":3949},[3772,7957,4059],{"class":3945},[3772,7959,5059],{"class":3949},[3772,7961,4059],{"class":3945},[3772,7963,7713],{"class":3949},[3772,7965,7818],{"class":3945},[3772,7967,7968],{"class":3934},"\u002F\u002F Пряма мутація draft-об'єкта!\n",[3772,7970,7971],{"class":3774,"line":4005},[3772,7972,7973],{"class":3945},"  }\n",[3772,7975,7976],{"class":3774,"line":4011},[3772,7977,4316],{"class":3945},[5417,7979,7980],{},[3762,7981,7983],{"className":5422,"code":7982,"language":5424,"meta":3767,"style":3767},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam defaultFontName \"Helvetica\"\nskinparam defaultFontSize 12\n\nactor \"Reducer Logic\" as Logic #bfdbfe\nparticipant \"Immer Draft (JS Proxy)\" as Proxy #fef08a\nparticipant \"Base State (Immutable)\" as Base #e2e8f0\nparticipant \"Next State (Produced Tree)\" as Next #bbf7d0\n\nLogic -> Proxy : 1. state.user.name = \"Олексій\"\nProxy -> Proxy : 2. Запис мутації у внутрішній патч-лог\nLogic -> Proxy : 3. state.items.push(newTrip)\nProxy -> Proxy : 4. Фіксація додавання нового елемента\n\nProxy -> Base : 5. Читання незмінених гілок стану\nBase --> Next : 6. Незмінені гілки залишаються тими самими за посиланням\nProxy --> Next : 7. Змінені гілки отримують нові об'єкти в пам'яті\n@enduml\n",[3769,7984,7985,7989,7993,7997,8001,8006,8010,8015,8020,8025,8030,8034,8039,8044,8049,8054,8058,8063,8068,8073],{"__ignoreMap":3767},[3772,7986,7987],{"class":3774,"line":3775},[3772,7988,5431],{},[3772,7990,7991],{"class":3774,"line":3938},[3772,7992,5436],{},[3772,7994,7995],{"class":3774,"line":3961},[3772,7996,5441],{},[3772,7998,7999],{"class":3774,"line":3968},[3772,8000,5446],{},[3772,8002,8003],{"class":3774,"line":3974},[3772,8004,8005],{},"skinparam defaultFontSize 12\n",[3772,8007,8008],{"class":3774,"line":3996},[3772,8009,3965],{"emptyLinePlaceholder":3964},[3772,8011,8012],{"class":3774,"line":4005},[3772,8013,8014],{},"actor \"Reducer Logic\" as Logic #bfdbfe\n",[3772,8016,8017],{"class":3774,"line":4011},[3772,8018,8019],{},"participant \"Immer Draft (JS Proxy)\" as Proxy #fef08a\n",[3772,8021,8022],{"class":3774,"line":4017},[3772,8023,8024],{},"participant \"Base State (Immutable)\" as Base #e2e8f0\n",[3772,8026,8027],{"class":3774,"line":4023},[3772,8028,8029],{},"participant \"Next State (Produced Tree)\" as Next #bbf7d0\n",[3772,8031,8032],{"class":3774,"line":4028},[3772,8033,3965],{"emptyLinePlaceholder":3964},[3772,8035,8036],{"class":3774,"line":4034},[3772,8037,8038],{},"Logic -> Proxy : 1. state.user.name = \"Олексій\"\n",[3772,8040,8041],{"class":3774,"line":4068},[3772,8042,8043],{},"Proxy -> Proxy : 2. Запис мутації у внутрішній патч-лог\n",[3772,8045,8046],{"class":3774,"line":4313},[3772,8047,8048],{},"Logic -> Proxy : 3. state.items.push(newTrip)\n",[3772,8050,8051],{"class":3774,"line":4470},[3772,8052,8053],{},"Proxy -> Proxy : 4. Фіксація додавання нового елемента\n",[3772,8055,8056],{"class":3774,"line":4879},[3772,8057,3965],{"emptyLinePlaceholder":3964},[3772,8059,8060],{"class":3774,"line":4892},[3772,8061,8062],{},"Proxy -> Base : 5. Читання незмінених гілок стану\n",[3772,8064,8065],{"class":3774,"line":4903},[3772,8066,8067],{},"Base --> Next : 6. Незмінені гілки залишаються тими самими за посиланням\n",[3772,8069,8070],{"class":3774,"line":4909},[3772,8071,8072],{},"Proxy --> Next : 7. Змінені гілки отримують нові об'єкти в пам'яті\n",[3772,8074,8075],{"class":3774,"line":5521},[3772,8076,5553],{},[4474,8078,8079,8084],{},[3743,8080,8081],{},[3829,8082,8083],{},"Два критичних правила роботи з Immer:",[4588,8085,8086,8266],{},[3836,8087,8088,8091],{},[3829,8089,8090],{},"Або мутуємо, або повертаємо нове значення:",[3762,8092,8094],{"className":3925,"code":8093,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОМИЛКА: Не можна одночасно мутувати draft і повертати значення!\nbadReducer(state, action) {\n  state.loading = false;\n  return action.payload; \u002F\u002F Кине помилку в рантаймі!\n}\n\n\u002F\u002F ✅ ПРАВИЛЬНО (варіант 1 — мутація draft):\ngoodReducer1(state, action) {\n  state.loading = false;\n  state.data = action.payload;\n}\n\n\u002F\u002F ✅ ПРАВИЛЬНО (варіант 2 — повернення абсолютно нового стану):\ngoodReducer2(state, action) {\n  return { loading: false, data: action.payload };\n}\n",[3769,8095,8096,8101,8116,8132,8148,8152,8156,8161,8176,8190,8209,8213,8217,8222,8237,8262],{"__ignoreMap":3767},[3772,8097,8098],{"class":3774,"line":3775},[3772,8099,8100],{"class":3934},"\u002F\u002F ❌ ПОМИЛКА: Не можна одночасно мутувати draft і повертати значення!\n",[3772,8102,8103,8106,8108,8110,8112,8114],{"class":3774,"line":3938},[3772,8104,8105],{"class":3778},"badReducer",[3772,8107,5150],{"class":3945},[3772,8109,5153],{"class":3949},[3772,8111,3847],{"class":3945},[3772,8113,5163],{"class":3949},[3772,8115,5166],{"class":3945},[3772,8117,8118,8121,8123,8125,8127,8129],{"class":3774,"line":3961},[3772,8119,8120],{"class":3949},"  state",[3772,8122,4059],{"class":3945},[3772,8124,6741],{"class":3949},[3772,8126,3988],{"class":3945},[3772,8128,4803],{"class":3980},[3772,8130,8131],{"class":3945},";\n",[3772,8133,8134,8137,8139,8141,8143,8145],{"class":3774,"line":3968},[3772,8135,8136],{"class":3941},"  return",[3772,8138,7262],{"class":3949},[3772,8140,4059],{"class":3945},[3772,8142,5059],{"class":3949},[3772,8144,7818],{"class":3945},[3772,8146,8147],{"class":3934},"\u002F\u002F Кине помилку в рантаймі!\n",[3772,8149,8150],{"class":3774,"line":3974},[3772,8151,4316],{"class":3945},[3772,8153,8154],{"class":3774,"line":3996},[3772,8155,3965],{"emptyLinePlaceholder":3964},[3772,8157,8158],{"class":3774,"line":4005},[3772,8159,8160],{"class":3934},"\u002F\u002F ✅ ПРАВИЛЬНО (варіант 1 — мутація draft):\n",[3772,8162,8163,8166,8168,8170,8172,8174],{"class":3774,"line":4011},[3772,8164,8165],{"class":3778},"goodReducer1",[3772,8167,5150],{"class":3945},[3772,8169,5153],{"class":3949},[3772,8171,3847],{"class":3945},[3772,8173,5163],{"class":3949},[3772,8175,5166],{"class":3945},[3772,8177,8178,8180,8182,8184,8186,8188],{"class":3774,"line":4017},[3772,8179,8120],{"class":3949},[3772,8181,4059],{"class":3945},[3772,8183,6741],{"class":3949},[3772,8185,3988],{"class":3945},[3772,8187,4803],{"class":3980},[3772,8189,8131],{"class":3945},[3772,8191,8192,8194,8196,8199,8201,8203,8205,8207],{"class":3774,"line":4023},[3772,8193,8120],{"class":3949},[3772,8195,4059],{"class":3945},[3772,8197,8198],{"class":3949},"data",[3772,8200,3988],{"class":3945},[3772,8202,5163],{"class":3949},[3772,8204,4059],{"class":3945},[3772,8206,5059],{"class":3949},[3772,8208,8131],{"class":3945},[3772,8210,8211],{"class":3774,"line":4028},[3772,8212,4316],{"class":3945},[3772,8214,8215],{"class":3774,"line":4034},[3772,8216,3965],{"emptyLinePlaceholder":3964},[3772,8218,8219],{"class":3774,"line":4068},[3772,8220,8221],{"class":3934},"\u002F\u002F ✅ ПРАВИЛЬНО (варіант 2 — повернення абсолютно нового стану):\n",[3772,8223,8224,8227,8229,8231,8233,8235],{"class":3774,"line":4313},[3772,8225,8226],{"class":3778},"goodReducer2",[3772,8228,5150],{"class":3945},[3772,8230,5153],{"class":3949},[3772,8232,3847],{"class":3945},[3772,8234,5163],{"class":3949},[3772,8236,5166],{"class":3945},[3772,8238,8239,8241,8243,8246,8248,8250,8253,8255,8257,8259],{"class":3774,"line":4470},[3772,8240,8136],{"class":3941},[3772,8242,3946],{"class":3945},[3772,8244,8245],{"class":3949},"loading:",[3772,8247,4279],{"class":3980},[3772,8249,3847],{"class":3945},[3772,8251,8252],{"class":3949},"data:",[3772,8254,7262],{"class":3949},[3772,8256,4059],{"class":3945},[3772,8258,5059],{"class":3949},[3772,8260,8261],{"class":3945}," };\n",[3772,8263,8264],{"class":3774,"line":4879},[3772,8265,4316],{"class":3945},[3836,8267,8268,8271,8272,8275,8276,8279,8280,4094,8282],{},[3829,8269,8270],{},"Дебаг об'єктів Draft у console.log:","\nЯкщо ви виведете ",[3769,8273,8274],{},"console.log(state)"," всередині редуктора, ви побачите нечитабельний Proxy-об'єкт. Для перегляду реального вмісту використовуйте утиліту ",[3769,8277,8278],{},"current()"," з ",[3769,8281,3842],{},[3762,8283,8285],{"className":3925,"code":8284,"language":3927,"meta":3767,"style":3767},"import { current } from '@reduxjs\u002Ftoolkit'\n\nmyReducer(state, action) {\n  console.log('Поточний стан:', current(state)); \u002F\u002F Покаже чистий JS-об'єкт!\n}\n",[3769,8286,8287,8302,8306,8321,8349],{"__ignoreMap":3767},[3772,8288,8289,8291,8293,8296,8298,8300],{"class":3774,"line":3775},[3772,8290,3942],{"class":3941},[3772,8292,3946],{"class":3945},[3772,8294,8295],{"class":3949},"current",[3772,8297,3952],{"class":3945},[3772,8299,3955],{"class":3941},[3772,8301,3958],{"class":3781},[3772,8303,8304],{"class":3774,"line":3938},[3772,8305,3965],{"emptyLinePlaceholder":3964},[3772,8307,8308,8311,8313,8315,8317,8319],{"class":3774,"line":3961},[3772,8309,8310],{"class":3778},"myReducer",[3772,8312,5150],{"class":3945},[3772,8314,5153],{"class":3949},[3772,8316,3847],{"class":3945},[3772,8318,5163],{"class":3949},[3772,8320,5166],{"class":3945},[3772,8322,8323,8326,8328,8330,8332,8335,8337,8339,8341,8343,8346],{"class":3774,"line":3968},[3772,8324,8325],{"class":3949},"  console",[3772,8327,4059],{"class":3945},[3772,8329,7289],{"class":3778},[3772,8331,5150],{"class":3945},[3772,8333,8334],{"class":3781},"'Поточний стан:'",[3772,8336,3847],{"class":3945},[3772,8338,8295],{"class":3778},[3772,8340,5150],{"class":3945},[3772,8342,5153],{"class":3949},[3772,8344,8345],{"class":3945},")); ",[3772,8347,8348],{"class":3934},"\u002F\u002F Покаже чистий JS-об'єкт!\n",[3772,8350,8351],{"class":3774,"line":3974},[3772,8352,4316],{"class":3945},[4495,8354],{},[3747,8356,8358,8359,8361],{"id":8357},"_3-slice-createslice-повний-розбір","3. Slice (",[3769,8360,3846],{},"): Повний розбір",[3743,8363,8364,8367],{},[3829,8365,8366],{},"Slice"," (з англ. \"зріз\", \"шматок\") — це логічно відокремлений модуль стану в Redux Toolkit, який об'єднує в собі:",[3833,8369,8370,8377,8386,8394],{},[3836,8371,8372,5179,8375,4669],{},[3829,8373,8374],{},"Початковий стан",[3769,8376,5158],{},[3836,8378,8379,8382,8383,4669],{},[3829,8380,8381],{},"Редюсери"," для внутрішніх дій (",[3769,8384,8385],{},"reducers",[3836,8387,8388,5179,8391,4669],{},[3829,8389,8390],{},"Обробники зовнішніх подій",[3769,8392,8393],{},"extraReducers",[3836,8395,8396],{},[3829,8397,8398],{},"Автоматично згенеровані action creators",[5075,8400,8401,8406,8413,8432],{},[3743,8402,8403],{},[3829,8404,8405],{},"Аналогія зі світу React:",[3743,8407,8408,8409,8412],{},"Якщо уявити Redux Store як велику базу даних, то Slice — це окрема ",[3829,8410,8411],{},"таблиця"," в цій базі.",[3833,8414,8415,8421,8426],{},[3836,8416,8417,8420],{},[3769,8418,8419],{},"userSlice"," → таблиця користувачів",[3836,8422,8423,8425],{},[3769,8424,6804],{}," → таблиця поїздок",[3836,8427,8428,8431],{},[3769,8429,8430],{},"settingsSlice"," → таблиця налаштувань",[3743,8433,8434],{},"Кожна таблиця має свою схему (initialState) та методи для роботи з даними (reducers).",[7025,8436,8438],{"id":8437},"анатомія-createslice-всі-параметри","Анатомія createSlice: Всі параметри",[3762,8440,8442],{"className":3925,"code":8441,"language":3927,"meta":3767,"style":3767},"import { createSlice, PayloadAction } from '@reduxjs\u002Ftoolkit'\n\ninterface Trip {\n    id: string\n    title: string\n    region: string\n    likes: number\n}\n\ninterface TripsState {\n    items: Trip[]\n    loading: boolean\n    error: string | null\n    selectedTripId: string | null\n}\n\nconst initialState: TripsState = {\n    items: [],\n    loading: false,\n    error: null,\n    selectedTripId: null,\n}\n\nexport const tripsSlice = createSlice({\n    \u002F\u002F 1️⃣ name — Назва slice (використовується у типах дій)\n    name: 'trips',\n\n    \u002F\u002F 2️⃣ initialState — Початковий стан slice\n    initialState,\n\n    \u002F\u002F 3️⃣ reducers — Внутрішні дії та їх обробники\n    reducers: {\n        \u002F\u002F Простий редюсер без payload\n        clearTrips(state) {\n            state.items = []\n        },\n\n        \u002F\u002F Редюсер з payload (типізований через PayloadAction)\n        addTrip(state, action: PayloadAction\u003CTrip>) {\n            state.items.unshift(action.payload)\n        },\n\n        \u002F\u002F Редюсер з підготовкою (prepare callback)\n        addTripWithAutoId: {\n            reducer(state, action: PayloadAction\u003CTrip>) {\n                state.items.unshift(action.payload)\n            },\n            prepare(title: string, region: string) {\n                return {\n                    payload: {\n                        id: nanoid(), \u002F\u002F Генерація ID\n                        title,\n                        region,\n                        likes: 0,\n                    },\n                }\n            },\n        },\n\n        \u002F\u002F Оновлення вкладеного поля\n        updateTripLikes(state, action: PayloadAction\u003C{ id: string; likes: number }>) {\n            const trip = state.items.find((t) => t.id === action.payload.id)\n            if (trip) {\n                trip.likes = action.payload.likes \u002F\u002F Immer дозволяє мутацію!\n            }\n        },\n\n        \u002F\u002F Видалення за ID\n        removeTrip(state, action: PayloadAction\u003Cstring>) {\n            state.items = state.items.filter((t) => t.id !== action.payload)\n        },\n    },\n\n    \u002F\u002F 4️⃣ extraReducers — Обробка зовнішніх дій\n    extraReducers: (builder) => {\n        \u002F\u002F Обробка асинхронних thunk-ів\n        builder\n            .addCase(fetchTripsThunk.pending, (state) => {\n                state.loading = true\n            })\n            .addCase(fetchTripsThunk.fulfilled, (state, action) => {\n                state.items = action.payload\n                state.loading = false\n            })\n    },\n})\n\n\u002F\u002F 5️⃣ Експорт згенерованих action creators\nexport const { clearTrips, addTrip, addTripWithAutoId, updateTripLikes, removeTrip } = tripsSlice.actions\n\n\u002F\u002F 6️⃣ Експорт reducer для підключення до store\nexport default tripsSlice.reducer\n",[3769,8443,8444,8462,8466,8474,8482,8490,8498,8508,8512,8516,8524,8534,8542,8554,8567,8571,8575,8587,8593,8601,8609,8618,8622,8626,8640,8645,8653,8657,8662,8668,8672,8677,8683,8688,8699,8710,8714,8718,8723,8745,8768,8772,8776,8781,8788,8811,8834,8839,8863,8871,8879,8892,8900,8908,8920,8926,8932,8937,8942,8947,8953,8990,9038,9050,9075,9080,9085,9090,9096,9119,9164,9169,9174,9179,9185,9204,9210,9216,9245,9258,9264,9294,9311,9325,9330,9335,9340,9345,9351,9389,9394,9400],{"__ignoreMap":3767},[3772,8445,8446,8448,8450,8452,8454,8456,8458,8460],{"class":3774,"line":3775},[3772,8447,3942],{"class":3941},[3772,8449,3946],{"class":3945},[3772,8451,3846],{"class":3949},[3772,8453,3847],{"class":3945},[3772,8455,6361],{"class":3949},[3772,8457,3952],{"class":3945},[3772,8459,3955],{"class":3941},[3772,8461,3958],{"class":3781},[3772,8463,8464],{"class":3774,"line":3938},[3772,8465,3965],{"emptyLinePlaceholder":3964},[3772,8467,8468,8470,8472],{"class":3774,"line":3961},[3772,8469,6376],{"class":3980},[3772,8471,6379],{"class":4042},[3772,8473,4002],{"class":3945},[3772,8475,8476,8478,8480],{"class":3774,"line":3968},[3772,8477,6386],{"class":3949},[3772,8479,4800],{"class":3945},[3772,8481,6391],{"class":4042},[3772,8483,8484,8486,8488],{"class":3774,"line":3974},[3772,8485,6396],{"class":3949},[3772,8487,4800],{"class":3945},[3772,8489,6391],{"class":4042},[3772,8491,8492,8494,8496],{"class":3774,"line":3996},[3772,8493,6405],{"class":3949},[3772,8495,4800],{"class":3945},[3772,8497,6391],{"class":4042},[3772,8499,8500,8503,8505],{"class":3774,"line":4005},[3772,8501,8502],{"class":3949},"    likes",[3772,8504,4800],{"class":3945},[3772,8506,8507],{"class":4042},"number\n",[3772,8509,8510],{"class":3774,"line":4011},[3772,8511,4316],{"class":3945},[3772,8513,8514],{"class":3774,"line":4017},[3772,8515,3965],{"emptyLinePlaceholder":3964},[3772,8517,8518,8520,8522],{"class":3774,"line":4023},[3772,8519,6376],{"class":3980},[3772,8521,6424],{"class":4042},[3772,8523,4002],{"class":3945},[3772,8525,8526,8528,8530,8532],{"class":3774,"line":4028},[3772,8527,6431],{"class":3949},[3772,8529,4800],{"class":3945},[3772,8531,6436],{"class":4042},[3772,8533,6439],{"class":3945},[3772,8535,8536,8538,8540],{"class":3774,"line":4034},[3772,8537,6444],{"class":3949},[3772,8539,4800],{"class":3945},[3772,8541,6449],{"class":4042},[3772,8543,8544,8546,8548,8550,8552],{"class":3774,"line":4068},[3772,8545,6454],{"class":3949},[3772,8547,4800],{"class":3945},[3772,8549,6459],{"class":4042},[3772,8551,6462],{"class":3945},[3772,8553,4816],{"class":4042},[3772,8555,8556,8559,8561,8563,8565],{"class":3774,"line":4313},[3772,8557,8558],{"class":3949},"    selectedTripId",[3772,8560,4800],{"class":3945},[3772,8562,6459],{"class":4042},[3772,8564,6462],{"class":3945},[3772,8566,4816],{"class":4042},[3772,8568,8569],{"class":3774,"line":4470},[3772,8570,4316],{"class":3945},[3772,8572,8573],{"class":3774,"line":4879},[3772,8574,3965],{"emptyLinePlaceholder":3964},[3772,8576,8577,8579,8581,8583,8585],{"class":3774,"line":4892},[3772,8578,5885],{"class":3980},[3772,8580,5888],{"class":3984},[3772,8582,4800],{"class":3945},[3772,8584,6483],{"class":4042},[3772,8586,5891],{"class":3945},[3772,8588,8589,8591],{"class":3774,"line":4903},[3772,8590,5385],{"class":3949},[3772,8592,5898],{"class":3945},[3772,8594,8595,8597,8599],{"class":3774,"line":4909},[3772,8596,5903],{"class":3949},[3772,8598,4279],{"class":3980},[3772,8600,4806],{"class":3945},[3772,8602,8603,8605,8607],{"class":3774,"line":5521},[3772,8604,5912],{"class":3949},[3772,8606,5915],{"class":3980},[3772,8608,4806],{"class":3945},[3772,8610,8611,8614,8616],{"class":3774,"line":5527},[3772,8612,8613],{"class":3949},"    selectedTripId:",[3772,8615,5915],{"class":3980},[3772,8617,4806],{"class":3945},[3772,8619,8620],{"class":3774,"line":5533},[3772,8621,4316],{"class":3945},[3772,8623,8624],{"class":3774,"line":5539},[3772,8625,3965],{"emptyLinePlaceholder":3964},[3772,8627,8628,8630,8632,8634,8636,8638],{"class":3774,"line":5545},[3772,8629,3977],{"class":3941},[3772,8631,3981],{"class":3980},[3772,8633,6529],{"class":3984},[3772,8635,3988],{"class":3945},[3772,8637,3846],{"class":3778},[3772,8639,3993],{"class":3945},[3772,8641,8642],{"class":3774,"line":5550},[3772,8643,8644],{"class":3934},"    \u002F\u002F 1️⃣ name — Назва slice (використовується у типах дій)\n",[3772,8646,8647,8649,8651],{"class":3774,"line":6121},[3772,8648,6540],{"class":3949},[3772,8650,6543],{"class":3781},[3772,8652,4806],{"class":3945},[3772,8654,8655],{"class":3774,"line":6131},[3772,8656,3965],{"emptyLinePlaceholder":3964},[3772,8658,8659],{"class":3774,"line":6136},[3772,8660,8661],{"class":3934},"    \u002F\u002F 2️⃣ initialState — Початковий стан slice\n",[3772,8663,8664,8666],{"class":3774,"line":6142},[3772,8665,6550],{"class":3949},[3772,8667,4806],{"class":3945},[3772,8669,8670],{"class":3774,"line":6150},[3772,8671,3965],{"emptyLinePlaceholder":3964},[3772,8673,8674],{"class":3774,"line":6157},[3772,8675,8676],{"class":3934},"    \u002F\u002F 3️⃣ reducers — Внутрішні дії та їх обробники\n",[3772,8678,8679,8681],{"class":3774,"line":6162},[3772,8680,6557],{"class":3949},[3772,8682,4002],{"class":3945},[3772,8684,8685],{"class":3774,"line":6629},[3772,8686,8687],{"class":3934},"        \u002F\u002F Простий редюсер без payload\n",[3772,8689,8690,8693,8695,8697],{"class":3774,"line":6653},[3772,8691,8692],{"class":3778},"        clearTrips",[3772,8694,5150],{"class":3945},[3772,8696,5153],{"class":3949},[3772,8698,5166],{"class":3945},[3772,8700,8701,8703,8705,8707],{"class":3774,"line":6698},[3772,8702,6598],{"class":3949},[3772,8704,4059],{"class":3945},[3772,8706,5237],{"class":3949},[3772,8708,8709],{"class":3945}," = []\n",[3772,8711,8712],{"class":3774,"line":6703},[3772,8713,6621],{"class":3945},[3772,8715,8716],{"class":3774,"line":6709},[3772,8717,3965],{"emptyLinePlaceholder":3964},[3772,8719,8720],{"class":3774,"line":6734},[3772,8721,8722],{"class":3934},"        \u002F\u002F Редюсер з payload (типізований через PayloadAction)\n",[3772,8724,8725,8727,8729,8731,8733,8735,8737,8739,8741,8743],{"class":3774,"line":6753},[3772,8726,6569],{"class":3778},[3772,8728,5150],{"class":3945},[3772,8730,5153],{"class":3949},[3772,8732,3847],{"class":3945},[3772,8734,5163],{"class":3949},[3772,8736,4800],{"class":3945},[3772,8738,6361],{"class":4042},[3772,8740,4051],{"class":3945},[3772,8742,6436],{"class":4042},[3772,8744,6588],{"class":3945},[3772,8746,8747,8749,8751,8753,8755,8758,8760,8762,8764,8766],{"class":3774,"line":6758},[3772,8748,6598],{"class":3949},[3772,8750,4059],{"class":3945},[3772,8752,5237],{"class":3949},[3772,8754,4059],{"class":3945},[3772,8756,8757],{"class":3778},"unshift",[3772,8759,5150],{"class":3945},[3772,8761,5163],{"class":3949},[3772,8763,4059],{"class":3945},[3772,8765,5059],{"class":3949},[3772,8767,5345],{"class":3945},[3772,8769,8770],{"class":3774,"line":6763},[3772,8771,6621],{"class":3945},[3772,8773,8774],{"class":3774,"line":6768},[3772,8775,3965],{"emptyLinePlaceholder":3964},[3772,8777,8778],{"class":3774,"line":6773},[3772,8779,8780],{"class":3934},"        \u002F\u002F Редюсер з підготовкою (prepare callback)\n",[3772,8782,8783,8786],{"class":3774,"line":6779},[3772,8784,8785],{"class":3949},"        addTripWithAutoId:",[3772,8787,4002],{"class":3945},[3772,8789,8790,8793,8795,8797,8799,8801,8803,8805,8807,8809],{"class":3774,"line":6812},[3772,8791,8792],{"class":3778},"            reducer",[3772,8794,5150],{"class":3945},[3772,8796,5153],{"class":3949},[3772,8798,3847],{"class":3945},[3772,8800,5163],{"class":3949},[3772,8802,4800],{"class":3945},[3772,8804,6361],{"class":4042},[3772,8806,4051],{"class":3945},[3772,8808,6436],{"class":4042},[3772,8810,6588],{"class":3945},[3772,8812,8813,8816,8818,8820,8822,8824,8826,8828,8830,8832],{"class":3774,"line":6817},[3772,8814,8815],{"class":3949},"                state",[3772,8817,4059],{"class":3945},[3772,8819,5237],{"class":3949},[3772,8821,4059],{"class":3945},[3772,8823,8757],{"class":3778},[3772,8825,5150],{"class":3945},[3772,8827,5163],{"class":3949},[3772,8829,4059],{"class":3945},[3772,8831,5059],{"class":3949},[3772,8833,5345],{"class":3945},[3772,8835,8836],{"class":3774,"line":6823},[3772,8837,8838],{"class":3945},"            },\n",[3772,8840,8842,8845,8847,8849,8851,8853,8855,8857,8859,8861],{"class":3774,"line":8841},48,[3772,8843,8844],{"class":3778},"            prepare",[3772,8846,5150],{"class":3945},[3772,8848,7131],{"class":3949},[3772,8850,4800],{"class":3945},[3772,8852,6459],{"class":4042},[3772,8854,3847],{"class":3945},[3772,8856,7140],{"class":3949},[3772,8858,4800],{"class":3945},[3772,8860,6459],{"class":4042},[3772,8862,5166],{"class":3945},[3772,8864,8866,8869],{"class":3774,"line":8865},49,[3772,8867,8868],{"class":3941},"                return",[3772,8870,4002],{"class":3945},[3772,8872,8874,8877],{"class":3774,"line":8873},50,[3772,8875,8876],{"class":3949},"                    payload:",[3772,8878,4002],{"class":3945},[3772,8880,8882,8885,8887,8889],{"class":3774,"line":8881},51,[3772,8883,8884],{"class":3949},"                        id:",[3772,8886,7171],{"class":3778},[3772,8888,7174],{"class":3945},[3772,8890,8891],{"class":3934},"\u002F\u002F Генерація ID\n",[3772,8893,8895,8898],{"class":3774,"line":8894},52,[3772,8896,8897],{"class":3949},"                        title",[3772,8899,4806],{"class":3945},[3772,8901,8903,8906],{"class":3774,"line":8902},53,[3772,8904,8905],{"class":3949},"                        region",[3772,8907,4806],{"class":3945},[3772,8909,8911,8914,8918],{"class":3774,"line":8910},54,[3772,8912,8913],{"class":3949},"                        likes:",[3772,8915,8917],{"class":8916},"sJj4R"," 0",[3772,8919,4806],{"class":3945},[3772,8921,8923],{"class":3774,"line":8922},55,[3772,8924,8925],{"class":3945},"                    },\n",[3772,8927,8929],{"class":3774,"line":8928},56,[3772,8930,8931],{"class":3945},"                }\n",[3772,8933,8935],{"class":3774,"line":8934},57,[3772,8936,8838],{"class":3945},[3772,8938,8940],{"class":3774,"line":8939},58,[3772,8941,6621],{"class":3945},[3772,8943,8945],{"class":3774,"line":8944},59,[3772,8946,3965],{"emptyLinePlaceholder":3964},[3772,8948,8950],{"class":3774,"line":8949},60,[3772,8951,8952],{"class":3934},"        \u002F\u002F Оновлення вкладеного поля\n",[3772,8954,8956,8959,8961,8963,8965,8967,8969,8971,8973,8975,8977,8979,8981,8984,8986,8988],{"class":3774,"line":8955},61,[3772,8957,8958],{"class":3778},"        updateTripLikes",[3772,8960,5150],{"class":3945},[3772,8962,5153],{"class":3949},[3772,8964,3847],{"class":3945},[3772,8966,5163],{"class":3949},[3772,8968,4800],{"class":3945},[3772,8970,6361],{"class":4042},[3772,8972,7809],{"class":3945},[3772,8974,5812],{"class":3949},[3772,8976,4800],{"class":3945},[3772,8978,6459],{"class":4042},[3772,8980,7818],{"class":3945},[3772,8982,8983],{"class":3949},"likes",[3772,8985,4800],{"class":3945},[3772,8987,7833],{"class":4042},[3772,8989,7836],{"class":3945},[3772,8991,8993,8996,8998,9000,9002,9004,9006,9008,9010,9012,9014,9016,9018,9020,9022,9024,9026,9028,9030,9032,9034,9036],{"class":3774,"line":8992},62,[3772,8994,8995],{"class":3980},"            const",[3772,8997,5788],{"class":3984},[3772,8999,3988],{"class":3945},[3772,9001,5153],{"class":3949},[3772,9003,4059],{"class":3945},[3772,9005,5237],{"class":3949},[3772,9007,4059],{"class":3945},[3772,9009,7856],{"class":3778},[3772,9011,6056],{"class":3945},[3772,9013,6059],{"class":3949},[3772,9015,5765],{"class":3945},[3772,9017,5768],{"class":3980},[3772,9019,6066],{"class":3949},[3772,9021,4059],{"class":3945},[3772,9023,5812],{"class":3949},[3772,9025,5188],{"class":3945},[3772,9027,5163],{"class":3949},[3772,9029,4059],{"class":3945},[3772,9031,5059],{"class":3949},[3772,9033,4059],{"class":3945},[3772,9035,5812],{"class":3949},[3772,9037,5345],{"class":3945},[3772,9039,9041,9044,9046,9048],{"class":3774,"line":9040},63,[3772,9042,9043],{"class":3941},"            if",[3772,9045,5179],{"class":3945},[3772,9047,5762],{"class":3949},[3772,9049,5166],{"class":3945},[3772,9051,9053,9056,9058,9060,9062,9064,9066,9068,9070,9072],{"class":3774,"line":9052},64,[3772,9054,9055],{"class":3949},"                trip",[3772,9057,4059],{"class":3945},[3772,9059,8983],{"class":3949},[3772,9061,3988],{"class":3945},[3772,9063,5163],{"class":3949},[3772,9065,4059],{"class":3945},[3772,9067,5059],{"class":3949},[3772,9069,4059],{"class":3945},[3772,9071,8983],{"class":3949},[3772,9073,9074],{"class":3934}," \u002F\u002F Immer дозволяє мутацію!\n",[3772,9076,9078],{"class":3774,"line":9077},65,[3772,9079,6016],{"class":3945},[3772,9081,9083],{"class":3774,"line":9082},66,[3772,9084,6621],{"class":3945},[3772,9086,9088],{"class":3774,"line":9087},67,[3772,9089,3965],{"emptyLinePlaceholder":3964},[3772,9091,9093],{"class":3774,"line":9092},68,[3772,9094,9095],{"class":3934},"        \u002F\u002F Видалення за ID\n",[3772,9097,9099,9101,9103,9105,9107,9109,9111,9113,9115,9117],{"class":3774,"line":9098},69,[3772,9100,6632],{"class":3778},[3772,9102,5150],{"class":3945},[3772,9104,5153],{"class":3949},[3772,9106,3847],{"class":3945},[3772,9108,5163],{"class":3949},[3772,9110,4800],{"class":3945},[3772,9112,6361],{"class":4042},[3772,9114,4051],{"class":3945},[3772,9116,6459],{"class":4042},[3772,9118,6588],{"class":3945},[3772,9120,9122,9124,9126,9128,9130,9132,9134,9136,9138,9140,9142,9144,9146,9148,9150,9152,9154,9156,9158,9160,9162],{"class":3774,"line":9121},70,[3772,9123,6598],{"class":3949},[3772,9125,4059],{"class":3945},[3772,9127,5237],{"class":3949},[3772,9129,3988],{"class":3945},[3772,9131,5153],{"class":3949},[3772,9133,4059],{"class":3945},[3772,9135,5237],{"class":3949},[3772,9137,4059],{"class":3945},[3772,9139,6053],{"class":3778},[3772,9141,6056],{"class":3945},[3772,9143,6059],{"class":3949},[3772,9145,5765],{"class":3945},[3772,9147,5768],{"class":3980},[3772,9149,6066],{"class":3949},[3772,9151,4059],{"class":3945},[3772,9153,5812],{"class":3949},[3772,9155,6073],{"class":3945},[3772,9157,5163],{"class":3949},[3772,9159,4059],{"class":3945},[3772,9161,5059],{"class":3949},[3772,9163,5345],{"class":3945},[3772,9165,9167],{"class":3774,"line":9166},71,[3772,9168,6621],{"class":3945},[3772,9170,9172],{"class":3774,"line":9171},72,[3772,9173,4014],{"class":3945},[3772,9175,9177],{"class":3774,"line":9176},73,[3772,9178,3965],{"emptyLinePlaceholder":3964},[3772,9180,9182],{"class":3774,"line":9181},74,[3772,9183,9184],{"class":3934},"    \u002F\u002F 4️⃣ extraReducers — Обробка зовнішніх дій\n",[3772,9186,9188,9191,9193,9195,9198,9200,9202],{"class":3774,"line":9187},75,[3772,9189,9190],{"class":3778},"    extraReducers",[3772,9192,4094],{"class":3949},[3772,9194,5179],{"class":3945},[3772,9196,9197],{"class":3949},"builder",[3772,9199,5765],{"class":3945},[3772,9201,5768],{"class":3980},[3772,9203,4002],{"class":3945},[3772,9205,9207],{"class":3774,"line":9206},76,[3772,9208,9209],{"class":3934},"        \u002F\u002F Обробка асинхронних thunk-ів\n",[3772,9211,9213],{"class":3774,"line":9212},77,[3772,9214,9215],{"class":3949},"        builder\n",[3772,9217,9219,9222,9225,9227,9230,9232,9235,9237,9239,9241,9243],{"class":3774,"line":9218},78,[3772,9220,9221],{"class":3945},"            .",[3772,9223,9224],{"class":3778},"addCase",[3772,9226,5150],{"class":3945},[3772,9228,9229],{"class":3949},"fetchTripsThunk",[3772,9231,4059],{"class":3945},[3772,9233,9234],{"class":3949},"pending",[3772,9236,7128],{"class":3945},[3772,9238,5153],{"class":3949},[3772,9240,5765],{"class":3945},[3772,9242,5768],{"class":3980},[3772,9244,4002],{"class":3945},[3772,9246,9248,9250,9252,9254,9256],{"class":3774,"line":9247},79,[3772,9249,8815],{"class":3949},[3772,9251,4059],{"class":3945},[3772,9253,6741],{"class":3949},[3772,9255,3988],{"class":3945},[3772,9257,4865],{"class":3980},[3772,9259,9261],{"class":3774,"line":9260},80,[3772,9262,9263],{"class":3945},"            })\n",[3772,9265,9267,9269,9271,9273,9275,9277,9280,9282,9284,9286,9288,9290,9292],{"class":3774,"line":9266},81,[3772,9268,9221],{"class":3945},[3772,9270,9224],{"class":3778},[3772,9272,5150],{"class":3945},[3772,9274,9229],{"class":3949},[3772,9276,4059],{"class":3945},[3772,9278,9279],{"class":3949},"fulfilled",[3772,9281,7128],{"class":3945},[3772,9283,5153],{"class":3949},[3772,9285,3847],{"class":3945},[3772,9287,5163],{"class":3949},[3772,9289,5765],{"class":3945},[3772,9291,5768],{"class":3980},[3772,9293,4002],{"class":3945},[3772,9295,9297,9299,9301,9303,9305,9307,9309],{"class":3774,"line":9296},82,[3772,9298,8815],{"class":3949},[3772,9300,4059],{"class":3945},[3772,9302,5237],{"class":3949},[3772,9304,3988],{"class":3945},[3772,9306,5163],{"class":3949},[3772,9308,4059],{"class":3945},[3772,9310,6750],{"class":3949},[3772,9312,9314,9316,9318,9320,9322],{"class":3774,"line":9313},83,[3772,9315,8815],{"class":3949},[3772,9317,4059],{"class":3945},[3772,9319,6741],{"class":3949},[3772,9321,3988],{"class":3945},[3772,9323,9324],{"class":3980},"false\n",[3772,9326,9328],{"class":3774,"line":9327},84,[3772,9329,9263],{"class":3945},[3772,9331,9333],{"class":3774,"line":9332},85,[3772,9334,4014],{"class":3945},[3772,9336,9338],{"class":3774,"line":9337},86,[3772,9339,4020],{"class":3945},[3772,9341,9343],{"class":3774,"line":9342},87,[3772,9344,3965],{"emptyLinePlaceholder":3964},[3772,9346,9348],{"class":3774,"line":9347},88,[3772,9349,9350],{"class":3934},"\u002F\u002F 5️⃣ Експорт згенерованих action creators\n",[3772,9352,9354,9356,9358,9360,9363,9365,9367,9369,9372,9374,9377,9379,9381,9383,9385,9387],{"class":3774,"line":9353},89,[3772,9355,3977],{"class":3941},[3772,9357,3981],{"class":3980},[3772,9359,3946],{"class":3945},[3772,9361,9362],{"class":3984},"clearTrips",[3772,9364,3847],{"class":3945},[3772,9366,6788],{"class":3984},[3772,9368,3847],{"class":3945},[3772,9370,9371],{"class":3984},"addTripWithAutoId",[3772,9373,3847],{"class":3945},[3772,9375,9376],{"class":3984},"updateTripLikes",[3772,9378,3847],{"class":3945},[3772,9380,6793],{"class":3984},[3772,9382,6801],{"class":3945},[3772,9384,6804],{"class":3949},[3772,9386,4059],{"class":3945},[3772,9388,6809],{"class":3949},[3772,9390,9392],{"class":3774,"line":9391},90,[3772,9393,3965],{"emptyLinePlaceholder":3964},[3772,9395,9397],{"class":3774,"line":9396},91,[3772,9398,9399],{"class":3934},"\u002F\u002F 6️⃣ Експорт reducer для підключення до store\n",[3772,9401,9403,9405,9407,9409,9411],{"class":3774,"line":9402},92,[3772,9404,3977],{"class":3941},[3772,9406,4196],{"class":3941},[3772,9408,6529],{"class":3949},[3772,9410,4059],{"class":3945},[3772,9412,6834],{"class":3949},[7025,9414,9416],{"id":9415},"детальний-розбір-кожної-секції","Детальний розбір кожної секції",[9418,9419,9421],"h5",{"id":9420},"_1-name-простір-імен-для-дій","1. name — Простір імен для дій",[3743,9423,9424,9425,9427,9428,9431],{},"Параметр ",[3769,9426,4838],{}," використовується як ",[3829,9429,9430],{},"префікс"," для всіх автоматично згенерованих типів дій:",[3762,9433,9435],{"className":3925,"code":9434,"language":3927,"meta":3767,"style":3767},"createSlice({\n    name: 'trips',\n    reducers: {\n        addTrip: ...,\n        removeTrip: ...\n    }\n})\n\n\u002F\u002F Згенеровані типи дій:\n\u002F\u002F - trips\u002FaddTrip\n\u002F\u002F - trips\u002FremoveTrip\n",[3769,9436,9437,9443,9451,9457,9465,9473,9477,9481,9485,9490,9495],{"__ignoreMap":3767},[3772,9438,9439,9441],{"class":3774,"line":3775},[3772,9440,3846],{"class":3778},[3772,9442,3993],{"class":3945},[3772,9444,9445,9447,9449],{"class":3774,"line":3938},[3772,9446,6540],{"class":3949},[3772,9448,6543],{"class":3781},[3772,9450,4806],{"class":3945},[3772,9452,9453,9455],{"class":3774,"line":3961},[3772,9454,6557],{"class":3949},[3772,9456,4002],{"class":3945},[3772,9458,9459,9462],{"class":3774,"line":3968},[3772,9460,9461],{"class":3949},"        addTrip:",[3772,9463,9464],{"class":3945}," ...,\n",[3772,9466,9467,9470],{"class":3774,"line":3974},[3772,9468,9469],{"class":3949},"        removeTrip:",[3772,9471,9472],{"class":3945}," ...\n",[3772,9474,9475],{"class":3774,"line":3996},[3772,9476,4906],{"class":3945},[3772,9478,9479],{"class":3774,"line":4005},[3772,9480,4020],{"class":3945},[3772,9482,9483],{"class":3774,"line":4011},[3772,9484,3965],{"emptyLinePlaceholder":3964},[3772,9486,9487],{"class":3774,"line":4017},[3772,9488,9489],{"class":3934},"\u002F\u002F Згенеровані типи дій:\n",[3772,9491,9492],{"class":3774,"line":4023},[3772,9493,9494],{"class":3934},"\u002F\u002F - trips\u002FaddTrip\n",[3772,9496,9497],{"class":3774,"line":4028},[3772,9498,9499],{"class":3934},"\u002F\u002F - trips\u002FremoveTrip\n",[4474,9501,9502,9507],{},[3743,9503,9504],{},[3829,9505,9506],{},"Правила найменування:",[3833,9508,9509,9525,9541,9561],{},[3836,9510,9511,9512,9515,9516,3847,9519,3847,9522],{},"✅ Використовуйте ",[3829,9513,9514],{},"singular"," (однина): ",[3769,9517,9518],{},"'trip'",[3769,9520,9521],{},"'user'",[3769,9523,9524],{},"'setting'",[3836,9526,9527,9528,9531,9532,3847,9535,3847,9538],{},"✅ Або ",[3829,9529,9530],{},"множина"," для колекцій: ",[3769,9533,9534],{},"'trips'",[3769,9536,9537],{},"'users'",[3769,9539,9540],{},"'settings'",[3836,9542,9543,9544,9546,9547,4800,9550,3847,9556],{},"❌ Уникайте префіксів ",[3769,9545,8366],{}," або ",[3769,9548,9549],{},"State",[9551,9552,9553],"del",{},[3769,9554,9555],{},"'tripsSlice'",[9551,9557,9558],{},[3769,9559,9560],{},"'tripsState'",[3836,9562,9563,9564,3847,9567],{},"✅ Використовуйте camelCase: ",[3769,9565,9566],{},"'userProfile'",[3769,9568,9569],{},"'appSettings'",[9418,9571,9573],{"id":9572},"_2-initialstate-початковий-стан","2. initialState — Початковий стан",[3743,9575,9576,9578],{},[3829,9577,8374],{}," визначає структуру даних та їх дефолтні значення:",[3762,9580,9582],{"className":3925,"code":9581,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Простий стан\nconst initialState = {\n    items: [],\n    loading: false,\n}\n\n\u002F\u002F Складний стан з TypeScript інтерфейсом\ninterface TripsState {\n    items: Trip[]\n    loading: boolean\n    error: string | null\n    filters: {\n        region: string\n        search: string\n    }\n    pagination: {\n        page: number\n        pageSize: number\n        total: number\n    }\n}\n\nconst initialState: TripsState = {\n    items: [],\n    loading: false,\n    error: null,\n    filters: {\n        region: 'all',\n        search: '',\n    },\n    pagination: {\n        page: 1,\n        pageSize: 20,\n        total: 0,\n    },\n}\n",[3769,9583,9584,9589,9597,9603,9611,9615,9619,9624,9632,9642,9650,9662,9669,9677,9686,9690,9697,9706,9715,9724,9728,9732,9736,9748,9754,9762,9770,9777,9787,9797,9801,9808,9818,9828,9837,9841],{"__ignoreMap":3767},[3772,9585,9586],{"class":3774,"line":3775},[3772,9587,9588],{"class":3934},"\u002F\u002F Простий стан\n",[3772,9590,9591,9593,9595],{"class":3774,"line":3938},[3772,9592,5885],{"class":3980},[3772,9594,5888],{"class":3984},[3772,9596,5891],{"class":3945},[3772,9598,9599,9601],{"class":3774,"line":3961},[3772,9600,5385],{"class":3949},[3772,9602,5898],{"class":3945},[3772,9604,9605,9607,9609],{"class":3774,"line":3968},[3772,9606,5903],{"class":3949},[3772,9608,4279],{"class":3980},[3772,9610,4806],{"class":3945},[3772,9612,9613],{"class":3774,"line":3974},[3772,9614,4316],{"class":3945},[3772,9616,9617],{"class":3774,"line":3996},[3772,9618,3965],{"emptyLinePlaceholder":3964},[3772,9620,9621],{"class":3774,"line":4005},[3772,9622,9623],{"class":3934},"\u002F\u002F Складний стан з TypeScript інтерфейсом\n",[3772,9625,9626,9628,9630],{"class":3774,"line":4011},[3772,9627,6376],{"class":3980},[3772,9629,6424],{"class":4042},[3772,9631,4002],{"class":3945},[3772,9633,9634,9636,9638,9640],{"class":3774,"line":4017},[3772,9635,6431],{"class":3949},[3772,9637,4800],{"class":3945},[3772,9639,6436],{"class":4042},[3772,9641,6439],{"class":3945},[3772,9643,9644,9646,9648],{"class":3774,"line":4023},[3772,9645,6444],{"class":3949},[3772,9647,4800],{"class":3945},[3772,9649,6449],{"class":4042},[3772,9651,9652,9654,9656,9658,9660],{"class":3774,"line":4028},[3772,9653,6454],{"class":3949},[3772,9655,4800],{"class":3945},[3772,9657,6459],{"class":4042},[3772,9659,6462],{"class":3945},[3772,9661,4816],{"class":4042},[3772,9663,9664,9667],{"class":3774,"line":4034},[3772,9665,9666],{"class":3949},"    filters",[3772,9668,4723],{"class":3945},[3772,9670,9671,9673,9675],{"class":3774,"line":4068},[3772,9672,5021],{"class":3949},[3772,9674,4800],{"class":3945},[3772,9676,6391],{"class":4042},[3772,9678,9679,9682,9684],{"class":3774,"line":4313},[3772,9680,9681],{"class":3949},"        search",[3772,9683,4800],{"class":3945},[3772,9685,6391],{"class":4042},[3772,9687,9688],{"class":3774,"line":4470},[3772,9689,4906],{"class":3945},[3772,9691,9692,9695],{"class":3774,"line":4879},[3772,9693,9694],{"class":3949},"    pagination",[3772,9696,4723],{"class":3945},[3772,9698,9699,9702,9704],{"class":3774,"line":4892},[3772,9700,9701],{"class":3949},"        page",[3772,9703,4800],{"class":3945},[3772,9705,8507],{"class":4042},[3772,9707,9708,9711,9713],{"class":3774,"line":4903},[3772,9709,9710],{"class":3949},"        pageSize",[3772,9712,4800],{"class":3945},[3772,9714,8507],{"class":4042},[3772,9716,9717,9720,9722],{"class":3774,"line":4909},[3772,9718,9719],{"class":3949},"        total",[3772,9721,4800],{"class":3945},[3772,9723,8507],{"class":4042},[3772,9725,9726],{"class":3774,"line":5521},[3772,9727,4906],{"class":3945},[3772,9729,9730],{"class":3774,"line":5527},[3772,9731,4316],{"class":3945},[3772,9733,9734],{"class":3774,"line":5533},[3772,9735,3965],{"emptyLinePlaceholder":3964},[3772,9737,9738,9740,9742,9744,9746],{"class":3774,"line":5539},[3772,9739,5885],{"class":3980},[3772,9741,5888],{"class":3984},[3772,9743,4800],{"class":3945},[3772,9745,6483],{"class":4042},[3772,9747,5891],{"class":3945},[3772,9749,9750,9752],{"class":3774,"line":5545},[3772,9751,5385],{"class":3949},[3772,9753,5898],{"class":3945},[3772,9755,9756,9758,9760],{"class":3774,"line":5550},[3772,9757,5903],{"class":3949},[3772,9759,4279],{"class":3980},[3772,9761,4806],{"class":3945},[3772,9763,9764,9766,9768],{"class":3774,"line":6121},[3772,9765,5912],{"class":3949},[3772,9767,5915],{"class":3980},[3772,9769,4806],{"class":3945},[3772,9771,9772,9775],{"class":3774,"line":6131},[3772,9773,9774],{"class":3949},"    filters:",[3772,9776,4002],{"class":3945},[3772,9778,9779,9782,9785],{"class":3774,"line":6136},[3772,9780,9781],{"class":3949},"        region:",[3772,9783,9784],{"class":3781}," 'all'",[3772,9786,4806],{"class":3945},[3772,9788,9789,9792,9795],{"class":3774,"line":6142},[3772,9790,9791],{"class":3949},"        search:",[3772,9793,9794],{"class":3781}," ''",[3772,9796,4806],{"class":3945},[3772,9798,9799],{"class":3774,"line":6150},[3772,9800,4014],{"class":3945},[3772,9802,9803,9806],{"class":3774,"line":6157},[3772,9804,9805],{"class":3949},"    pagination:",[3772,9807,4002],{"class":3945},[3772,9809,9810,9813,9816],{"class":3774,"line":6162},[3772,9811,9812],{"class":3949},"        page:",[3772,9814,9815],{"class":8916}," 1",[3772,9817,4806],{"class":3945},[3772,9819,9820,9823,9826],{"class":3774,"line":6629},[3772,9821,9822],{"class":3949},"        pageSize:",[3772,9824,9825],{"class":8916}," 20",[3772,9827,4806],{"class":3945},[3772,9829,9830,9833,9835],{"class":3774,"line":6653},[3772,9831,9832],{"class":3949},"        total:",[3772,9834,8917],{"class":8916},[3772,9836,4806],{"class":3945},[3772,9838,9839],{"class":3774,"line":6698},[3772,9840,4014],{"class":3945},[3772,9842,9843],{"class":3774,"line":6703},[3772,9844,4316],{"class":3945},[5075,9846,9847,9852],{},[3743,9848,9849],{},[3829,9850,9851],{},"Best Practices для initialState:",[4588,9853,9854,9863,9875,9881],{},[3836,9855,9856,9859,9860],{},[3829,9857,9858],{},"Завжди ініціалізуйте всі поля"," — не залишайте ",[3769,9861,9862],{},"undefined",[3836,9864,9865,9872,9873],{},[3829,9866,9867,9868,9871],{},"Використовуйте ",[3769,9869,9870],{},"null"," для відсутніх даних"," замість ",[3769,9874,9862],{},[3836,9876,9877,9880],{},[3829,9878,9879],{},"Серіалізовані типи"," — тільки JSON-сумісні значення",[3836,9882,9883,9886,9887],{},[3829,9884,9885],{},"Дати як рядки"," — ISO 8601 формат: ",[3769,9888,9889],{},"'2026-08-29T10:00:00.000Z'",[9418,9891,9893],{"id":9892},"_3-reducers-внутрішні-дії-slice","3. reducers — Внутрішні дії slice",[3743,9895,9896,9897,9899,9900,9903],{},"Редюсери в ",[3769,9898,8385],{}," автоматично генерують ",[3829,9901,9902],{},"action creators"," з тим самим іменем:",[3762,9905,9907],{"className":3925,"code":9906,"language":3927,"meta":3767,"style":3767},"reducers: {\n    \u002F\u002F 1. Редюсер без аргументів\n    clearTrips(state) {\n        state.items = []\n    }\n}\n\n\u002F\u002F Використання:\ndispatch(clearTrips())  \u002F\u002F Викликаємо БЕЗ аргументів\n\n\u002F\u002F Згенерована дія:\n\u002F\u002F { type: 'trips\u002FclearTrips' }\n",[3769,9908,9909,9915,9920,9931,9942,9946,9950,9954,9958,9973,9977,9982],{"__ignoreMap":3767},[3772,9910,9911,9913],{"class":3774,"line":3775},[3772,9912,8385],{"class":4719},[3772,9914,4723],{"class":3945},[3772,9916,9917],{"class":3774,"line":3938},[3772,9918,9919],{"class":3934},"    \u002F\u002F 1. Редюсер без аргументів\n",[3772,9921,9922,9925,9927,9929],{"class":3774,"line":3961},[3772,9923,9924],{"class":3778},"    clearTrips",[3772,9926,5150],{"class":3945},[3772,9928,5153],{"class":3949},[3772,9930,5166],{"class":3945},[3772,9932,9933,9936,9938,9940],{"class":3774,"line":3968},[3772,9934,9935],{"class":3949},"        state",[3772,9937,4059],{"class":3945},[3772,9939,5237],{"class":3949},[3772,9941,8709],{"class":3945},[3772,9943,9944],{"class":3774,"line":3974},[3772,9945,4906],{"class":3945},[3772,9947,9948],{"class":3774,"line":3996},[3772,9949,4316],{"class":3945},[3772,9951,9952],{"class":3774,"line":4005},[3772,9953,3965],{"emptyLinePlaceholder":3964},[3772,9955,9956],{"class":3774,"line":4011},[3772,9957,7255],{"class":3934},[3772,9959,9960,9963,9965,9967,9970],{"class":3774,"line":4017},[3772,9961,9962],{"class":3778},"dispatch",[3772,9964,5150],{"class":3945},[3772,9966,9362],{"class":3778},[3772,9968,9969],{"class":3945},"())  ",[3772,9971,9972],{"class":3934},"\u002F\u002F Викликаємо БЕЗ аргументів\n",[3772,9974,9975],{"class":3774,"line":4023},[3772,9976,3965],{"emptyLinePlaceholder":3964},[3772,9978,9979],{"class":3774,"line":4028},[3772,9980,9981],{"class":3934},"\u002F\u002F Згенерована дія:\n",[3772,9983,9984],{"class":3774,"line":4034},[3772,9985,9986],{"class":3934},"\u002F\u002F { type: 'trips\u002FclearTrips' }\n",[3762,9988,9990],{"className":3925,"code":9989,"language":3927,"meta":3767,"style":3767},"reducers: {\n    \u002F\u002F 2. Редюсер з одним аргументом\n    addTrip(state, action: PayloadAction\u003CTrip>) {\n        state.items.push(action.payload)\n    }\n}\n\n\u002F\u002F Використання:\ndispatch(addTrip({ id: '1', title: 'Київ' }))\n\n\u002F\u002F Згенерована дія:\n\u002F\u002F {\n\u002F\u002F   type: 'trips\u002FaddTrip',\n\u002F\u002F   payload: { id: '1', title: 'Київ' }\n\u002F\u002F }\n",[3769,9991,9992,9998,10003,10026,10048,10052,10056,10060,10064,10089,10093,10097,10101,10106,10111],{"__ignoreMap":3767},[3772,9993,9994,9996],{"class":3774,"line":3775},[3772,9995,8385],{"class":4719},[3772,9997,4723],{"class":3945},[3772,9999,10000],{"class":3774,"line":3938},[3772,10001,10002],{"class":3934},"    \u002F\u002F 2. Редюсер з одним аргументом\n",[3772,10004,10005,10008,10010,10012,10014,10016,10018,10020,10022,10024],{"class":3774,"line":3961},[3772,10006,10007],{"class":3778},"    addTrip",[3772,10009,5150],{"class":3945},[3772,10011,5153],{"class":3949},[3772,10013,3847],{"class":3945},[3772,10015,5163],{"class":3949},[3772,10017,4800],{"class":3945},[3772,10019,6361],{"class":3949},[3772,10021,4051],{"class":3945},[3772,10023,6436],{"class":3949},[3772,10025,6588],{"class":3945},[3772,10027,10028,10030,10032,10034,10036,10038,10040,10042,10044,10046],{"class":3774,"line":3968},[3772,10029,9935],{"class":3949},[3772,10031,4059],{"class":3945},[3772,10033,5237],{"class":3949},[3772,10035,4059],{"class":3945},[3772,10037,5337],{"class":3778},[3772,10039,5150],{"class":3945},[3772,10041,5163],{"class":3949},[3772,10043,4059],{"class":3945},[3772,10045,5059],{"class":3949},[3772,10047,5345],{"class":3945},[3772,10049,10050],{"class":3774,"line":3974},[3772,10051,4906],{"class":3945},[3772,10053,10054],{"class":3774,"line":3996},[3772,10055,4316],{"class":3945},[3772,10057,10058],{"class":3774,"line":4005},[3772,10059,3965],{"emptyLinePlaceholder":3964},[3772,10061,10062],{"class":3774,"line":4011},[3772,10063,7255],{"class":3934},[3772,10065,10066,10068,10070,10072,10075,10077,10079,10081,10083,10086],{"class":3774,"line":4017},[3772,10067,9962],{"class":3778},[3772,10069,5150],{"class":3945},[3772,10071,6788],{"class":3778},[3772,10073,10074],{"class":3945},"({ ",[3772,10076,4739],{"class":3949},[3772,10078,4742],{"class":3781},[3772,10080,3847],{"class":3945},[3772,10082,4747],{"class":3949},[3772,10084,10085],{"class":3781}," 'Київ'",[3772,10087,10088],{"class":3945}," }))\n",[3772,10090,10091],{"class":3774,"line":4023},[3772,10092,3965],{"emptyLinePlaceholder":3964},[3772,10094,10095],{"class":3774,"line":4028},[3772,10096,9981],{"class":3934},[3772,10098,10099],{"class":3774,"line":4034},[3772,10100,7300],{"class":3934},[3772,10102,10103],{"class":3774,"line":4068},[3772,10104,10105],{"class":3934},"\u002F\u002F   type: 'trips\u002FaddTrip',\n",[3772,10107,10108],{"class":3774,"line":4313},[3772,10109,10110],{"class":3934},"\u002F\u002F   payload: { id: '1', title: 'Київ' }\n",[3772,10112,10113],{"class":3774,"line":4470},[3772,10114,7320],{"class":3934},[3762,10116,10118],{"className":3925,"code":10117,"language":3927,"meta":3767,"style":3767},"reducers: {\n    \u002F\u002F 3. Редюсер з prepare callback (багато аргументів)\n    addTripWithMetadata: {\n        reducer(state, action: PayloadAction\u003CTrip>) {\n            state.items.push(action.payload)\n        },\n        prepare(title: string, region: string, userId: string) {\n            return {\n                payload: {\n                    id: nanoid(),\n                    title,\n                    region,\n                    createdAt: new Date().toISOString(),\n                    createdBy: userId\n                }\n            }\n        }\n    }\n}\n\n\u002F\u002F Використання:\ndispatch(addTripWithMetadata('Карпати', 'Захід', 'user-123'))\n\n\u002F\u002F Згенерована дія:\n\u002F\u002F {\n\u002F\u002F   type: 'trips\u002FaddTripWithMetadata',\n\u002F\u002F   payload: {\n\u002F\u002F     id: 'V1StGXR8_Z5jd...',\n\u002F\u002F     title: 'Карпати',\n\u002F\u002F     region: 'Захід',\n\u002F\u002F     createdAt: '2026-08-29T10:30:00.000Z',\n\u002F\u002F     createdBy: 'user-123'\n\u002F\u002F   }\n\u002F\u002F }\n",[3769,10119,10120,10126,10131,10138,10161,10183,10187,10219,10225,10232,10242,10249,10256,10271,10279,10283,10287,10291,10295,10299,10303,10307,10332,10336,10340,10344,10349,10354,10359,10364,10369,10374,10379,10384],{"__ignoreMap":3767},[3772,10121,10122,10124],{"class":3774,"line":3775},[3772,10123,8385],{"class":4719},[3772,10125,4723],{"class":3945},[3772,10127,10128],{"class":3774,"line":3938},[3772,10129,10130],{"class":3934},"    \u002F\u002F 3. Редюсер з prepare callback (багато аргументів)\n",[3772,10132,10133,10136],{"class":3774,"line":3961},[3772,10134,10135],{"class":4719},"    addTripWithMetadata",[3772,10137,4723],{"class":3945},[3772,10139,10140,10143,10145,10147,10149,10151,10153,10155,10157,10159],{"class":3774,"line":3968},[3772,10141,10142],{"class":3778},"        reducer",[3772,10144,5150],{"class":3945},[3772,10146,5153],{"class":3949},[3772,10148,3847],{"class":3945},[3772,10150,5163],{"class":3949},[3772,10152,4800],{"class":3945},[3772,10154,6361],{"class":3949},[3772,10156,4051],{"class":3945},[3772,10158,6436],{"class":3949},[3772,10160,6588],{"class":3945},[3772,10162,10163,10165,10167,10169,10171,10173,10175,10177,10179,10181],{"class":3774,"line":3974},[3772,10164,6598],{"class":3949},[3772,10166,4059],{"class":3945},[3772,10168,5237],{"class":3949},[3772,10170,4059],{"class":3945},[3772,10172,5337],{"class":3778},[3772,10174,5150],{"class":3945},[3772,10176,5163],{"class":3949},[3772,10178,4059],{"class":3945},[3772,10180,5059],{"class":3949},[3772,10182,5345],{"class":3945},[3772,10184,10185],{"class":3774,"line":3996},[3772,10186,6621],{"class":3945},[3772,10188,10189,10192,10194,10196,10198,10200,10202,10204,10206,10208,10210,10213,10215,10217],{"class":3774,"line":4005},[3772,10190,10191],{"class":3778},"        prepare",[3772,10193,5150],{"class":3945},[3772,10195,7131],{"class":3949},[3772,10197,4800],{"class":3945},[3772,10199,6459],{"class":3949},[3772,10201,3847],{"class":3945},[3772,10203,7140],{"class":3949},[3772,10205,4800],{"class":3945},[3772,10207,6459],{"class":3949},[3772,10209,3847],{"class":3945},[3772,10211,10212],{"class":3949},"userId",[3772,10214,4800],{"class":3945},[3772,10216,6459],{"class":3949},[3772,10218,5166],{"class":3945},[3772,10220,10221,10223],{"class":3774,"line":4011},[3772,10222,5977],{"class":3941},[3772,10224,4002],{"class":3945},[3772,10226,10227,10230],{"class":3774,"line":4017},[3772,10228,10229],{"class":3949},"                payload:",[3772,10231,4002],{"class":3945},[3772,10233,10234,10237,10239],{"class":3774,"line":4023},[3772,10235,10236],{"class":3949},"                    id:",[3772,10238,7171],{"class":3778},[3772,10240,10241],{"class":3945},"(),\n",[3772,10243,10244,10247],{"class":3774,"line":4028},[3772,10245,10246],{"class":3949},"                    title",[3772,10248,4806],{"class":3945},[3772,10250,10251,10254],{"class":3774,"line":4034},[3772,10252,10253],{"class":3949},"                    region",[3772,10255,4806],{"class":3945},[3772,10257,10258,10261,10263,10265,10267,10269],{"class":3774,"line":4068},[3772,10259,10260],{"class":3949},"                    createdAt:",[3772,10262,7199],{"class":3980},[3772,10264,7202],{"class":3778},[3772,10266,7205],{"class":3945},[3772,10268,7208],{"class":3778},[3772,10270,10241],{"class":3945},[3772,10272,10273,10276],{"class":3774,"line":4313},[3772,10274,10275],{"class":3949},"                    createdBy:",[3772,10277,10278],{"class":3949}," userId\n",[3772,10280,10281],{"class":3774,"line":4470},[3772,10282,8931],{"class":3945},[3772,10284,10285],{"class":3774,"line":4879},[3772,10286,6016],{"class":3945},[3772,10288,10289],{"class":3774,"line":4892},[3772,10290,5245],{"class":3945},[3772,10292,10293],{"class":3774,"line":4903},[3772,10294,4906],{"class":3945},[3772,10296,10297],{"class":3774,"line":4909},[3772,10298,4316],{"class":3945},[3772,10300,10301],{"class":3774,"line":5521},[3772,10302,3965],{"emptyLinePlaceholder":3964},[3772,10304,10305],{"class":3774,"line":5527},[3772,10306,7255],{"class":3934},[3772,10308,10309,10311,10313,10316,10318,10320,10322,10324,10326,10329],{"class":3774,"line":5533},[3772,10310,9962],{"class":3778},[3772,10312,5150],{"class":3945},[3772,10314,10315],{"class":3778},"addTripWithMetadata",[3772,10317,5150],{"class":3945},[3772,10319,7272],{"class":3781},[3772,10321,3847],{"class":3945},[3772,10323,7277],{"class":3781},[3772,10325,3847],{"class":3945},[3772,10327,10328],{"class":3781},"'user-123'",[3772,10330,10331],{"class":3945},"))\n",[3772,10333,10334],{"class":3774,"line":5539},[3772,10335,3965],{"emptyLinePlaceholder":3964},[3772,10337,10338],{"class":3774,"line":5545},[3772,10339,9981],{"class":3934},[3772,10341,10342],{"class":3774,"line":5550},[3772,10343,7300],{"class":3934},[3772,10345,10346],{"class":3774,"line":6121},[3772,10347,10348],{"class":3934},"\u002F\u002F   type: 'trips\u002FaddTripWithMetadata',\n",[3772,10350,10351],{"class":3774,"line":6131},[3772,10352,10353],{"class":3934},"\u002F\u002F   payload: {\n",[3772,10355,10356],{"class":3774,"line":6136},[3772,10357,10358],{"class":3934},"\u002F\u002F     id: 'V1StGXR8_Z5jd...',\n",[3772,10360,10361],{"class":3774,"line":6142},[3772,10362,10363],{"class":3934},"\u002F\u002F     title: 'Карпати',\n",[3772,10365,10366],{"class":3774,"line":6150},[3772,10367,10368],{"class":3934},"\u002F\u002F     region: 'Захід',\n",[3772,10370,10371],{"class":3774,"line":6157},[3772,10372,10373],{"class":3934},"\u002F\u002F     createdAt: '2026-08-29T10:30:00.000Z',\n",[3772,10375,10376],{"class":3774,"line":6162},[3772,10377,10378],{"class":3934},"\u002F\u002F     createdBy: 'user-123'\n",[3772,10380,10381],{"class":3774,"line":6629},[3772,10382,10383],{"class":3934},"\u002F\u002F   }\n",[3772,10385,10386],{"class":3774,"line":6653},[3772,10387,7320],{"class":3934},[3875,10389,10390,10395,10410],{},[3743,10391,10392],{},[3829,10393,10394],{},"Чому потрібен prepare callback?",[3743,10396,10397,10398,10401,10402,10405,10406,10409],{},"Редюсери мають бути ",[3829,10399,10400],{},"чистими функціями"," — не можуть генерувати випадкові значення або дати. Функція ",[3769,10403,10404],{},"prepare"," виконується ",[3829,10407,10408],{},"до"," редюсера і може:",[3833,10411,10412,10420,10425,10428],{},[3836,10413,10414,10415,3847,10417,4669],{},"Генерувати ID (",[3769,10416,7454],{},[3769,10418,10419],{},"uuid()",[3836,10421,10422,10423,4669],{},"Додавати timestamps (",[3769,10424,7460],{},[3836,10426,10427],{},"Валідувати вхідні дані",[3836,10429,10430],{},"Трансформувати аргументи в payload",[9418,10432,10434],{"id":10433},"типові-патерни-роботи-зі-станом","Типові патерни роботи зі станом",[3762,10436,10438],{"className":3925,"code":10437,"language":3927,"meta":3767,"style":3767},"reducers: {\n    \u002F\u002F Додавання елемента на початок\n    addTripToStart(state, action: PayloadAction\u003CTrip>) {\n        state.items.unshift(action.payload)  \u002F\u002F Immer дозволяє!\n    },\n\n    \u002F\u002F Оновлення за ID\n    updateTrip(state, action: PayloadAction\u003C{ id: string; changes: Partial\u003CTrip> }>) {\n        const { id, changes } = action.payload\n        const trip = state.items.find(t => t.id === id)\n        if (trip) {\n            Object.assign(trip, changes)  \u002F\u002F Immer дозволяє!\n        }\n    },\n\n    \u002F\u002F Видалення за умовою\n    removeCompletedTrips(state) {\n        state.items = state.items.filter(t => !t.isCompleted)\n    },\n\n    \u002F\u002F Оновлення вкладеного об'єкта\n    updateFilter(state, action: PayloadAction\u003C{ key: keyof Filters; value: string }>) {\n        const { key, value } = action.payload\n        state.filters[key] = value\n    },\n\n    \u002F\u002F Скидання до початкового стану\n    resetTrips(state) {\n        return initialState  \u002F\u002F Повертаємо новий об'єкт\n    }\n}\n",[3769,10439,10440,10446,10451,10474,10500,10504,10508,10513,10553,10574,10610,10621,10643,10647,10651,10655,10660,10671,10709,10713,10717,10722,10761,10782,10802,10806,10810,10815,10826,10835,10839],{"__ignoreMap":3767},[3772,10441,10442,10444],{"class":3774,"line":3775},[3772,10443,8385],{"class":4719},[3772,10445,4723],{"class":3945},[3772,10447,10448],{"class":3774,"line":3938},[3772,10449,10450],{"class":3934},"    \u002F\u002F Додавання елемента на початок\n",[3772,10452,10453,10456,10458,10460,10462,10464,10466,10468,10470,10472],{"class":3774,"line":3961},[3772,10454,10455],{"class":3778},"    addTripToStart",[3772,10457,5150],{"class":3945},[3772,10459,5153],{"class":3949},[3772,10461,3847],{"class":3945},[3772,10463,5163],{"class":3949},[3772,10465,4800],{"class":3945},[3772,10467,6361],{"class":3949},[3772,10469,4051],{"class":3945},[3772,10471,6436],{"class":3949},[3772,10473,6588],{"class":3945},[3772,10475,10476,10478,10480,10482,10484,10486,10488,10490,10492,10494,10497],{"class":3774,"line":3968},[3772,10477,9935],{"class":3949},[3772,10479,4059],{"class":3945},[3772,10481,5237],{"class":3949},[3772,10483,4059],{"class":3945},[3772,10485,8757],{"class":3778},[3772,10487,5150],{"class":3945},[3772,10489,5163],{"class":3949},[3772,10491,4059],{"class":3945},[3772,10493,5059],{"class":3949},[3772,10495,10496],{"class":3945},")  ",[3772,10498,10499],{"class":3934},"\u002F\u002F Immer дозволяє!\n",[3772,10501,10502],{"class":3774,"line":3974},[3772,10503,4014],{"class":3945},[3772,10505,10506],{"class":3774,"line":3996},[3772,10507,3965],{"emptyLinePlaceholder":3964},[3772,10509,10510],{"class":3774,"line":4005},[3772,10511,10512],{"class":3934},"    \u002F\u002F Оновлення за ID\n",[3772,10514,10515,10518,10520,10522,10524,10526,10528,10530,10532,10534,10536,10538,10541,10543,10546,10548,10550],{"class":3774,"line":4011},[3772,10516,10517],{"class":3778},"    updateTrip",[3772,10519,5150],{"class":3945},[3772,10521,5153],{"class":3949},[3772,10523,3847],{"class":3945},[3772,10525,5163],{"class":3949},[3772,10527,4800],{"class":3945},[3772,10529,6361],{"class":3949},[3772,10531,7809],{"class":3945},[3772,10533,4739],{"class":3949},[3772,10535,7815],{"class":3949},[3772,10537,7818],{"class":3945},[3772,10539,10540],{"class":3949},"changes",[3772,10542,4800],{"class":3945},[3772,10544,10545],{"class":3949},"Partial",[3772,10547,4051],{"class":3945},[3772,10549,6436],{"class":3949},[3772,10551,10552],{"class":3945},"> }>) {\n",[3772,10554,10555,10558,10560,10562,10564,10566,10568,10570,10572],{"class":3774,"line":4017},[3772,10556,10557],{"class":3980},"        const",[3772,10559,3946],{"class":3945},[3772,10561,5812],{"class":3984},[3772,10563,3847],{"class":3945},[3772,10565,10540],{"class":3984},[3772,10567,6801],{"class":3945},[3772,10569,5163],{"class":3949},[3772,10571,4059],{"class":3945},[3772,10573,6750],{"class":3949},[3772,10575,10576,10578,10580,10582,10584,10586,10588,10590,10592,10594,10596,10598,10600,10602,10604,10606,10608],{"class":3774,"line":4023},[3772,10577,10557],{"class":3980},[3772,10579,5788],{"class":3984},[3772,10581,3988],{"class":3945},[3772,10583,5153],{"class":3949},[3772,10585,4059],{"class":3945},[3772,10587,5237],{"class":3949},[3772,10589,4059],{"class":3945},[3772,10591,7856],{"class":3778},[3772,10593,5150],{"class":3945},[3772,10595,6059],{"class":3949},[3772,10597,7863],{"class":3980},[3772,10599,6066],{"class":3949},[3772,10601,4059],{"class":3945},[3772,10603,5812],{"class":3949},[3772,10605,5188],{"class":3945},[3772,10607,5812],{"class":3949},[3772,10609,5345],{"class":3945},[3772,10611,10612,10615,10617,10619],{"class":3774,"line":4028},[3772,10613,10614],{"class":3941},"        if",[3772,10616,5179],{"class":3945},[3772,10618,5762],{"class":3949},[3772,10620,5166],{"class":3945},[3772,10622,10623,10626,10628,10631,10633,10635,10637,10639,10641],{"class":3774,"line":4034},[3772,10624,10625],{"class":3949},"            Object",[3772,10627,4059],{"class":3945},[3772,10629,10630],{"class":3778},"assign",[3772,10632,5150],{"class":3945},[3772,10634,5762],{"class":3949},[3772,10636,3847],{"class":3945},[3772,10638,10540],{"class":3949},[3772,10640,10496],{"class":3945},[3772,10642,10499],{"class":3934},[3772,10644,10645],{"class":3774,"line":4068},[3772,10646,5245],{"class":3945},[3772,10648,10649],{"class":3774,"line":4313},[3772,10650,4014],{"class":3945},[3772,10652,10653],{"class":3774,"line":4470},[3772,10654,3965],{"emptyLinePlaceholder":3964},[3772,10656,10657],{"class":3774,"line":4879},[3772,10658,10659],{"class":3934},"    \u002F\u002F Видалення за умовою\n",[3772,10661,10662,10665,10667,10669],{"class":3774,"line":4892},[3772,10663,10664],{"class":3778},"    removeCompletedTrips",[3772,10666,5150],{"class":3945},[3772,10668,5153],{"class":3949},[3772,10670,5166],{"class":3945},[3772,10672,10673,10675,10677,10679,10681,10683,10685,10687,10689,10691,10693,10695,10697,10700,10702,10704,10707],{"class":3774,"line":4903},[3772,10674,9935],{"class":3949},[3772,10676,4059],{"class":3945},[3772,10678,5237],{"class":3949},[3772,10680,3988],{"class":3945},[3772,10682,5153],{"class":3949},[3772,10684,4059],{"class":3945},[3772,10686,5237],{"class":3949},[3772,10688,4059],{"class":3945},[3772,10690,6053],{"class":3778},[3772,10692,5150],{"class":3945},[3772,10694,6059],{"class":3949},[3772,10696,7863],{"class":3980},[3772,10698,10699],{"class":3945}," !",[3772,10701,6059],{"class":3949},[3772,10703,4059],{"class":3945},[3772,10705,10706],{"class":3949},"isCompleted",[3772,10708,5345],{"class":3945},[3772,10710,10711],{"class":3774,"line":4909},[3772,10712,4014],{"class":3945},[3772,10714,10715],{"class":3774,"line":5521},[3772,10716,3965],{"emptyLinePlaceholder":3964},[3772,10718,10719],{"class":3774,"line":5527},[3772,10720,10721],{"class":3934},"    \u002F\u002F Оновлення вкладеного об'єкта\n",[3772,10723,10724,10727,10729,10731,10733,10735,10737,10739,10741,10744,10747,10750,10752,10755,10757,10759],{"class":3774,"line":5533},[3772,10725,10726],{"class":3778},"    updateFilter",[3772,10728,5150],{"class":3945},[3772,10730,5153],{"class":3949},[3772,10732,3847],{"class":3945},[3772,10734,5163],{"class":3949},[3772,10736,4800],{"class":3945},[3772,10738,6361],{"class":3949},[3772,10740,7809],{"class":3945},[3772,10742,10743],{"class":3949},"key:",[3772,10745,10746],{"class":3949}," keyof",[3772,10748,10749],{"class":3949}," Filters",[3772,10751,7818],{"class":3945},[3772,10753,10754],{"class":3949},"value",[3772,10756,4800],{"class":3945},[3772,10758,6459],{"class":3949},[3772,10760,7836],{"class":3945},[3772,10762,10763,10765,10767,10770,10772,10774,10776,10778,10780],{"class":3774,"line":5539},[3772,10764,10557],{"class":3980},[3772,10766,3946],{"class":3945},[3772,10768,10769],{"class":3984},"key",[3772,10771,3847],{"class":3945},[3772,10773,10754],{"class":3984},[3772,10775,6801],{"class":3945},[3772,10777,5163],{"class":3949},[3772,10779,4059],{"class":3945},[3772,10781,6750],{"class":3949},[3772,10783,10784,10786,10788,10791,10794,10796,10799],{"class":3774,"line":5545},[3772,10785,9935],{"class":3949},[3772,10787,4059],{"class":3945},[3772,10789,10790],{"class":3949},"filters",[3772,10792,10793],{"class":3945},"[",[3772,10795,10769],{"class":3949},[3772,10797,10798],{"class":3945},"] = ",[3772,10800,10801],{"class":3949},"value\n",[3772,10803,10804],{"class":3774,"line":5550},[3772,10805,4014],{"class":3945},[3772,10807,10808],{"class":3774,"line":6121},[3772,10809,3965],{"emptyLinePlaceholder":3964},[3772,10811,10812],{"class":3774,"line":6131},[3772,10813,10814],{"class":3934},"    \u002F\u002F Скидання до початкового стану\n",[3772,10816,10817,10820,10822,10824],{"class":3774,"line":6136},[3772,10818,10819],{"class":3778},"    resetTrips",[3772,10821,5150],{"class":3945},[3772,10823,5153],{"class":3949},[3772,10825,5166],{"class":3945},[3772,10827,10828,10830,10832],{"class":3774,"line":6142},[3772,10829,5202],{"class":3941},[3772,10831,5888],{"class":3949},[3772,10833,10834],{"class":3934},"  \u002F\u002F Повертаємо новий об'єкт\n",[3772,10836,10837],{"class":3774,"line":6150},[3772,10838,4906],{"class":3945},[3772,10840,10841],{"class":3774,"line":6157},[3772,10842,4316],{"class":3945},[10844,10845,10846,10993,11287],"accordion",{},[10847,10848,10851,10856,10859],"accordion-item",{"icon":10849,"label":10850},"i-lucide-alert-triangle","Чи можна мутувати state напряму?",[3743,10852,6851,10853],{},[3829,10854,10855],{},"Так, але ТІЛЬКИ всередині reducers у createSlice!",[3743,10857,10858],{},"Immer автоматично перетворює мутації в іммутабельні операції:",[3762,10860,10862],{"className":3925,"code":10861,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ✅ МОЖНА (всередині createSlice):\nreducers: {\n    addTrip(state, action) {\n        state.items.push(action.payload)  \u002F\u002F Працює завдяки Immer!\n    }\n}\n\n\u002F\u002F ❌ НЕ МОЖНА (поза createSlice):\nfunction MyComponent() {\n    const trips = useAppSelector(state => state.trips.items)\n    trips.push(newTrip)  \u002F\u002F ❌ ПОМИЛКА! Мутація стану!\n}\n",[3769,10863,10864,10869,10875,10889,10914,10918,10922,10926,10931,10940,10971,10989],{"__ignoreMap":3767},[3772,10865,10866],{"class":3774,"line":3775},[3772,10867,10868],{"class":3934},"\u002F\u002F ✅ МОЖНА (всередині createSlice):\n",[3772,10870,10871,10873],{"class":3774,"line":3938},[3772,10872,8385],{"class":4719},[3772,10874,4723],{"class":3945},[3772,10876,10877,10879,10881,10883,10885,10887],{"class":3774,"line":3961},[3772,10878,10007],{"class":3778},[3772,10880,5150],{"class":3945},[3772,10882,5153],{"class":3949},[3772,10884,3847],{"class":3945},[3772,10886,5163],{"class":3949},[3772,10888,5166],{"class":3945},[3772,10890,10891,10893,10895,10897,10899,10901,10903,10905,10907,10909,10911],{"class":3774,"line":3968},[3772,10892,9935],{"class":3949},[3772,10894,4059],{"class":3945},[3772,10896,5237],{"class":3949},[3772,10898,4059],{"class":3945},[3772,10900,5337],{"class":3778},[3772,10902,5150],{"class":3945},[3772,10904,5163],{"class":3949},[3772,10906,4059],{"class":3945},[3772,10908,5059],{"class":3949},[3772,10910,10496],{"class":3945},[3772,10912,10913],{"class":3934},"\u002F\u002F Працює завдяки Immer!\n",[3772,10915,10916],{"class":3774,"line":3974},[3772,10917,4906],{"class":3945},[3772,10919,10920],{"class":3774,"line":3996},[3772,10921,4316],{"class":3945},[3772,10923,10924],{"class":3774,"line":4005},[3772,10925,3965],{"emptyLinePlaceholder":3964},[3772,10927,10928],{"class":3774,"line":4011},[3772,10929,10930],{"class":3934},"\u002F\u002F ❌ НЕ МОЖНА (поза createSlice):\n",[3772,10932,10933,10935,10938],{"class":3774,"line":4017},[3772,10934,5144],{"class":3980},[3772,10936,10937],{"class":3778}," MyComponent",[3772,10939,4205],{"class":3945},[3772,10941,10942,10945,10948,10950,10953,10955,10957,10959,10961,10963,10965,10967,10969],{"class":3774,"line":4023},[3772,10943,10944],{"class":3980},"    const",[3772,10946,10947],{"class":3984}," trips",[3772,10949,3988],{"class":3945},[3772,10951,10952],{"class":3778},"useAppSelector",[3772,10954,5150],{"class":3945},[3772,10956,5153],{"class":3949},[3772,10958,7863],{"class":3980},[3772,10960,5353],{"class":3949},[3772,10962,4059],{"class":3945},[3772,10964,7557],{"class":3949},[3772,10966,4059],{"class":3945},[3772,10968,5237],{"class":3949},[3772,10970,5345],{"class":3945},[3772,10972,10973,10975,10977,10979,10981,10984,10986],{"class":3774,"line":4028},[3772,10974,4720],{"class":3949},[3772,10976,4059],{"class":3945},[3772,10978,5337],{"class":3778},[3772,10980,5150],{"class":3945},[3772,10982,10983],{"class":3949},"newTrip",[3772,10985,10496],{"class":3945},[3772,10987,10988],{"class":3934},"\u002F\u002F ❌ ПОМИЛКА! Мутація стану!\n",[3772,10990,10991],{"class":3774,"line":4034},[3772,10992,4316],{"class":3945},[10847,10994,10996,10999],{"icon":943,"label":10995},"Як оновити глибоко вкладене поле?",[3743,10997,10998],{},"Завдяки Immer можна писати як звичайний JavaScript:",[3762,11000,11002],{"className":3925,"code":11001,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Стан:\n\u002F\u002F state.trips.items[0].places[0].rating = 3\n\n\u002F\u002F Старий Redux (складно читати):\nreturn {\n    ...state,\n    items: state.items.map((trip, index) =>\n        index === 0\n            ? {\n                ...trip,\n                places: trip.places.map((place, pIndex) =>\n                    pIndex === 0\n                        ? { ...place, rating: 5 }\n                        : place\n                )\n            }\n            : trip\n    )\n}\n\n\u002F\u002F Redux Toolkit (просто і зрозуміло):\nupdatePlaceRating(state, action: PayloadAction\u003C{ tripIndex: number; placeIndex: number; rating: number }>) {\n    const { tripIndex, placeIndex, rating } = action.payload\n    state.items[tripIndex].places[placeIndex].rating = rating\n}\n",[3769,11003,11004,11009,11014,11018,11023,11029,11037,11065,11075,11080,11088,11116,11125,11142,11150,11155,11159,11167,11171,11175,11179,11184,11227,11252,11283],{"__ignoreMap":3767},[3772,11005,11006],{"class":3774,"line":3775},[3772,11007,11008],{"class":3934},"\u002F\u002F Стан:\n",[3772,11010,11011],{"class":3774,"line":3938},[3772,11012,11013],{"class":3934},"\u002F\u002F state.trips.items[0].places[0].rating = 3\n",[3772,11015,11016],{"class":3774,"line":3961},[3772,11017,3965],{"emptyLinePlaceholder":3964},[3772,11019,11020],{"class":3774,"line":3968},[3772,11021,11022],{"class":3934},"\u002F\u002F Старий Redux (складно читати):\n",[3772,11024,11025,11027],{"class":3774,"line":3974},[3772,11026,5350],{"class":3941},[3772,11028,4002],{"class":3945},[3772,11030,11031,11033,11035],{"class":3774,"line":3996},[3772,11032,5376],{"class":3945},[3772,11034,5153],{"class":3949},[3772,11036,4806],{"class":3945},[3772,11038,11039,11041,11043,11045,11047,11049,11051,11053,11055,11057,11060,11062],{"class":3774,"line":4005},[3772,11040,5385],{"class":3949},[3772,11042,5353],{"class":3949},[3772,11044,4059],{"class":3945},[3772,11046,5237],{"class":3949},[3772,11048,4059],{"class":3945},[3772,11050,7562],{"class":3778},[3772,11052,6056],{"class":3945},[3772,11054,5762],{"class":3949},[3772,11056,3847],{"class":3945},[3772,11058,11059],{"class":3949},"index",[3772,11061,5765],{"class":3945},[3772,11063,11064],{"class":3980},"=>\n",[3772,11066,11067,11070,11072],{"class":3774,"line":4011},[3772,11068,11069],{"class":3949},"        index",[3772,11071,5188],{"class":3945},[3772,11073,11074],{"class":8916},"0\n",[3772,11076,11077],{"class":3774,"line":4017},[3772,11078,11079],{"class":3945},"            ? {\n",[3772,11081,11082,11084,11086],{"class":3774,"line":4023},[3772,11083,5984],{"class":3945},[3772,11085,5762],{"class":3949},[3772,11087,4806],{"class":3945},[3772,11089,11090,11093,11095,11097,11099,11101,11103,11105,11107,11109,11112,11114],{"class":3774,"line":4028},[3772,11091,11092],{"class":3949},"                places:",[3772,11094,5788],{"class":3949},[3772,11096,4059],{"class":3945},[3772,11098,7633],{"class":3949},[3772,11100,4059],{"class":3945},[3772,11102,7562],{"class":3778},[3772,11104,6056],{"class":3945},[3772,11106,7642],{"class":3949},[3772,11108,3847],{"class":3945},[3772,11110,11111],{"class":3949},"pIndex",[3772,11113,5765],{"class":3945},[3772,11115,11064],{"class":3980},[3772,11117,11118,11121,11123],{"class":3774,"line":4034},[3772,11119,11120],{"class":3949},"                    pIndex",[3772,11122,5188],{"class":3945},[3772,11124,11074],{"class":8916},[3772,11126,11127,11130,11132,11134,11137,11140],{"class":3774,"line":4068},[3772,11128,11129],{"class":3945},"                        ? { ...",[3772,11131,7642],{"class":3949},[3772,11133,3847],{"class":3945},[3772,11135,11136],{"class":3949},"rating:",[3772,11138,11139],{"class":8916}," 5",[3772,11141,4787],{"class":3945},[3772,11143,11144,11147],{"class":3774,"line":4313},[3772,11145,11146],{"class":3945},"                        : ",[3772,11148,11149],{"class":3949},"place\n",[3772,11151,11152],{"class":3774,"line":4470},[3772,11153,11154],{"class":3945},"                )\n",[3772,11156,11157],{"class":3774,"line":4879},[3772,11158,6016],{"class":3945},[3772,11160,11161,11164],{"class":3774,"line":4892},[3772,11162,11163],{"class":3945},"            : ",[3772,11165,11166],{"class":3949},"trip\n",[3772,11168,11169],{"class":3774,"line":4903},[3772,11170,4310],{"class":3945},[3772,11172,11173],{"class":3774,"line":4909},[3772,11174,4316],{"class":3945},[3772,11176,11177],{"class":3774,"line":5521},[3772,11178,3965],{"emptyLinePlaceholder":3964},[3772,11180,11181],{"class":3774,"line":5527},[3772,11182,11183],{"class":3934},"\u002F\u002F Redux Toolkit (просто і зрозуміло):\n",[3772,11185,11186,11188,11190,11192,11194,11196,11198,11200,11202,11205,11208,11210,11213,11215,11217,11219,11221,11223,11225],{"class":3774,"line":5533},[3772,11187,7794],{"class":3778},[3772,11189,5150],{"class":3945},[3772,11191,5153],{"class":3949},[3772,11193,3847],{"class":3945},[3772,11195,5163],{"class":3949},[3772,11197,4800],{"class":3945},[3772,11199,6361],{"class":3949},[3772,11201,7809],{"class":3945},[3772,11203,11204],{"class":3949},"tripIndex:",[3772,11206,11207],{"class":3949}," number",[3772,11209,7818],{"class":3945},[3772,11211,11212],{"class":3949},"placeIndex",[3772,11214,4800],{"class":3945},[3772,11216,7833],{"class":3949},[3772,11218,7818],{"class":3945},[3772,11220,7713],{"class":3949},[3772,11222,4800],{"class":3945},[3772,11224,7833],{"class":3949},[3772,11226,7836],{"class":3945},[3772,11228,11229,11231,11233,11236,11238,11240,11242,11244,11246,11248,11250],{"class":3774,"line":5539},[3772,11230,10944],{"class":3980},[3772,11232,3946],{"class":3945},[3772,11234,11235],{"class":3984},"tripIndex",[3772,11237,3847],{"class":3945},[3772,11239,11212],{"class":3984},[3772,11241,3847],{"class":3945},[3772,11243,7713],{"class":3984},[3772,11245,6801],{"class":3945},[3772,11247,5163],{"class":3949},[3772,11249,4059],{"class":3945},[3772,11251,6750],{"class":3949},[3772,11253,11254,11257,11259,11261,11263,11265,11268,11270,11272,11274,11276,11278,11280],{"class":3774,"line":5545},[3772,11255,11256],{"class":3949},"    state",[3772,11258,4059],{"class":3945},[3772,11260,5237],{"class":3949},[3772,11262,10793],{"class":3945},[3772,11264,11235],{"class":3949},[3772,11266,11267],{"class":3945},"].",[3772,11269,7633],{"class":3949},[3772,11271,10793],{"class":3945},[3772,11273,11212],{"class":3949},[3772,11275,11267],{"class":3945},[3772,11277,7713],{"class":3949},[3772,11279,3988],{"class":3945},[3772,11281,11282],{"class":3949},"rating\n",[3772,11284,11285],{"class":3774,"line":5550},[3772,11286,4316],{"class":3945},[10847,11288,11291,11294],{"icon":11289,"label":11290},"i-lucide-x-circle","Чому не можна одночасно мутувати і повертати значення?",[3743,11292,11293],{},"Це обмеження Immer:",[3762,11295,11297],{"className":3925,"code":11296,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОМИЛКА:\nbadReducer(state, action) {\n    state.loading = false      \u002F\u002F Мутація\n    return action.payload      \u002F\u002F І повернення нового стану\n}\n\u002F\u002F Помилка: \"Cannot return value while mutating draft\"\n\n\u002F\u002F ✅ ВАРІАНТ 1 — Тільки мутація:\ngoodReducer1(state, action) {\n    state.loading = false\n    state.data = action.payload\n}\n\n\u002F\u002F ✅ ВАРІАНТ 2 — Тільки повернення:\ngoodReducer2(state, action) {\n    return {\n        loading: false,\n        data: action.payload\n    }\n}\n",[3769,11298,11299,11304,11318,11333,11346,11350,11355,11359,11364,11378,11390,11406,11410,11414,11419,11433,11439,11448,11459,11463],{"__ignoreMap":3767},[3772,11300,11301],{"class":3774,"line":3775},[3772,11302,11303],{"class":3934},"\u002F\u002F ❌ ПОМИЛКА:\n",[3772,11305,11306,11308,11310,11312,11314,11316],{"class":3774,"line":3938},[3772,11307,8105],{"class":3778},[3772,11309,5150],{"class":3945},[3772,11311,5153],{"class":3949},[3772,11313,3847],{"class":3945},[3772,11315,5163],{"class":3949},[3772,11317,5166],{"class":3945},[3772,11319,11320,11322,11324,11326,11328,11330],{"class":3774,"line":3961},[3772,11321,11256],{"class":3949},[3772,11323,4059],{"class":3945},[3772,11325,6741],{"class":3949},[3772,11327,3988],{"class":3945},[3772,11329,4803],{"class":3980},[3772,11331,11332],{"class":3934},"      \u002F\u002F Мутація\n",[3772,11334,11335,11337,11339,11341,11343],{"class":3774,"line":3968},[3772,11336,4210],{"class":3941},[3772,11338,7262],{"class":3949},[3772,11340,4059],{"class":3945},[3772,11342,5059],{"class":3949},[3772,11344,11345],{"class":3934},"      \u002F\u002F І повернення нового стану\n",[3772,11347,11348],{"class":3774,"line":3974},[3772,11349,4316],{"class":3945},[3772,11351,11352],{"class":3774,"line":3996},[3772,11353,11354],{"class":3934},"\u002F\u002F Помилка: \"Cannot return value while mutating draft\"\n",[3772,11356,11357],{"class":3774,"line":4005},[3772,11358,3965],{"emptyLinePlaceholder":3964},[3772,11360,11361],{"class":3774,"line":4011},[3772,11362,11363],{"class":3934},"\u002F\u002F ✅ ВАРІАНТ 1 — Тільки мутація:\n",[3772,11365,11366,11368,11370,11372,11374,11376],{"class":3774,"line":4017},[3772,11367,8165],{"class":3778},[3772,11369,5150],{"class":3945},[3772,11371,5153],{"class":3949},[3772,11373,3847],{"class":3945},[3772,11375,5163],{"class":3949},[3772,11377,5166],{"class":3945},[3772,11379,11380,11382,11384,11386,11388],{"class":3774,"line":4023},[3772,11381,11256],{"class":3949},[3772,11383,4059],{"class":3945},[3772,11385,6741],{"class":3949},[3772,11387,3988],{"class":3945},[3772,11389,9324],{"class":3980},[3772,11391,11392,11394,11396,11398,11400,11402,11404],{"class":3774,"line":4028},[3772,11393,11256],{"class":3949},[3772,11395,4059],{"class":3945},[3772,11397,8198],{"class":3949},[3772,11399,3988],{"class":3945},[3772,11401,5163],{"class":3949},[3772,11403,4059],{"class":3945},[3772,11405,6750],{"class":3949},[3772,11407,11408],{"class":3774,"line":4034},[3772,11409,4316],{"class":3945},[3772,11411,11412],{"class":3774,"line":4068},[3772,11413,3965],{"emptyLinePlaceholder":3964},[3772,11415,11416],{"class":3774,"line":4313},[3772,11417,11418],{"class":3934},"\u002F\u002F ✅ ВАРІАНТ 2 — Тільки повернення:\n",[3772,11420,11421,11423,11425,11427,11429,11431],{"class":3774,"line":4470},[3772,11422,8226],{"class":3778},[3772,11424,5150],{"class":3945},[3772,11426,5153],{"class":3949},[3772,11428,3847],{"class":3945},[3772,11430,5163],{"class":3949},[3772,11432,5166],{"class":3945},[3772,11434,11435,11437],{"class":3774,"line":4879},[3772,11436,4210],{"class":3941},[3772,11438,4002],{"class":3945},[3772,11440,11441,11444,11446],{"class":3774,"line":4892},[3772,11442,11443],{"class":3949},"        loading:",[3772,11445,4279],{"class":3980},[3772,11447,4806],{"class":3945},[3772,11449,11450,11453,11455,11457],{"class":3774,"line":4903},[3772,11451,11452],{"class":3949},"        data:",[3772,11454,7262],{"class":3949},[3772,11456,4059],{"class":3945},[3772,11458,6750],{"class":3949},[3772,11460,11461],{"class":3774,"line":4909},[3772,11462,4906],{"class":3945},[3772,11464,11465],{"class":3774,"line":5521},[3772,11466,4316],{"class":3945},[7025,11468,11470,11471],{"id":11469},"розширений-синтаксис-редюсерів-з-prepare","Розширений синтаксис редюсерів з ",[3769,11472,10404],{},[3743,11474,11475,11476,11478,11479,4094],{},"Якщо дія вимагає генерації унікального ID або попередньої обробки аргументів перед попаданням у редуктор, ",[3769,11477,3846],{}," підтримує об'єктний синтаксис ",[3769,11480,11481],{},"{ reducer, prepare }",[3762,11483,11485],{"className":3925,"code":11484,"language":3927,"meta":3767,"style":3767},"import { createSlice, PayloadAction, nanoid } from '@reduxjs\u002Ftoolkit'\n\ninterface TripItem {\n    id: string\n    title: string\n    createdAt: string\n}\n\ninterface TripsState {\n    list: TripItem[]\n}\n\nconst initialState: TripsState = { list: [] }\n\nexport const tripsSlice = createSlice({\n    name: 'trips',\n    initialState,\n    reducers: {\n        \u002F\u002F Простий редюсер\n        clearAllTrips(state) {\n            state.list = []\n        },\n\n        \u002F\u002F Редюсер з функцією попередньої підготовки (prepare)\n        addTripWithAutoId: {\n            reducer(state, action: PayloadAction\u003CTripItem>) {\n                state.list.unshift(action.payload)\n            },\n            prepare(title: string) {\n                return {\n                    payload: {\n                        id: nanoid(),\n                        title,\n                        createdAt: new Date().toISOString(),\n                    },\n                }\n            },\n        },\n    },\n})\n\nexport const { clearAllTrips, addTripWithAutoId } = tripsSlice.actions\nexport default tripsSlice.reducer\n",[3769,11486,11487,11509,11513,11522,11530,11538,11547,11551,11555,11563,11575,11579,11583,11601,11605,11619,11627,11633,11639,11644,11655,11666,11670,11674,11679,11685,11707,11729,11733,11747,11753,11759,11767,11773,11788,11792,11796,11800,11804,11808,11812,11816,11839],{"__ignoreMap":3767},[3772,11488,11489,11491,11493,11495,11497,11499,11501,11503,11505,11507],{"class":3774,"line":3775},[3772,11490,3942],{"class":3941},[3772,11492,3946],{"class":3945},[3772,11494,3846],{"class":3949},[3772,11496,3847],{"class":3945},[3772,11498,6361],{"class":3949},[3772,11500,3847],{"class":3945},[3772,11502,7058],{"class":3949},[3772,11504,3952],{"class":3945},[3772,11506,3955],{"class":3941},[3772,11508,3958],{"class":3781},[3772,11510,11511],{"class":3774,"line":3938},[3772,11512,3965],{"emptyLinePlaceholder":3964},[3772,11514,11515,11517,11520],{"class":3774,"line":3961},[3772,11516,6376],{"class":3980},[3772,11518,11519],{"class":4042}," TripItem",[3772,11521,4002],{"class":3945},[3772,11523,11524,11526,11528],{"class":3774,"line":3968},[3772,11525,6386],{"class":3949},[3772,11527,4800],{"class":3945},[3772,11529,6391],{"class":4042},[3772,11531,11532,11534,11536],{"class":3774,"line":3974},[3772,11533,6396],{"class":3949},[3772,11535,4800],{"class":3945},[3772,11537,6391],{"class":4042},[3772,11539,11540,11543,11545],{"class":3774,"line":3996},[3772,11541,11542],{"class":3949},"    createdAt",[3772,11544,4800],{"class":3945},[3772,11546,6391],{"class":4042},[3772,11548,11549],{"class":3774,"line":4005},[3772,11550,4316],{"class":3945},[3772,11552,11553],{"class":3774,"line":4011},[3772,11554,3965],{"emptyLinePlaceholder":3964},[3772,11556,11557,11559,11561],{"class":3774,"line":4017},[3772,11558,6376],{"class":3980},[3772,11560,6424],{"class":4042},[3772,11562,4002],{"class":3945},[3772,11564,11565,11568,11570,11573],{"class":3774,"line":4023},[3772,11566,11567],{"class":3949},"    list",[3772,11569,4800],{"class":3945},[3772,11571,11572],{"class":4042},"TripItem",[3772,11574,6439],{"class":3945},[3772,11576,11577],{"class":3774,"line":4028},[3772,11578,4316],{"class":3945},[3772,11580,11581],{"class":3774,"line":4034},[3772,11582,3965],{"emptyLinePlaceholder":3964},[3772,11584,11585,11587,11589,11591,11593,11595,11598],{"class":3774,"line":4068},[3772,11586,5885],{"class":3980},[3772,11588,5888],{"class":3984},[3772,11590,4800],{"class":3945},[3772,11592,6483],{"class":4042},[3772,11594,7352],{"class":3945},[3772,11596,11597],{"class":3949},"list:",[3772,11599,11600],{"class":3945}," [] }\n",[3772,11602,11603],{"class":3774,"line":4313},[3772,11604,3965],{"emptyLinePlaceholder":3964},[3772,11606,11607,11609,11611,11613,11615,11617],{"class":3774,"line":4470},[3772,11608,3977],{"class":3941},[3772,11610,3981],{"class":3980},[3772,11612,6529],{"class":3984},[3772,11614,3988],{"class":3945},[3772,11616,3846],{"class":3778},[3772,11618,3993],{"class":3945},[3772,11620,11621,11623,11625],{"class":3774,"line":4879},[3772,11622,6540],{"class":3949},[3772,11624,6543],{"class":3781},[3772,11626,4806],{"class":3945},[3772,11628,11629,11631],{"class":3774,"line":4892},[3772,11630,6550],{"class":3949},[3772,11632,4806],{"class":3945},[3772,11634,11635,11637],{"class":3774,"line":4903},[3772,11636,6557],{"class":3949},[3772,11638,4002],{"class":3945},[3772,11640,11641],{"class":3774,"line":4909},[3772,11642,11643],{"class":3934},"        \u002F\u002F Простий редюсер\n",[3772,11645,11646,11649,11651,11653],{"class":3774,"line":5521},[3772,11647,11648],{"class":3778},"        clearAllTrips",[3772,11650,5150],{"class":3945},[3772,11652,5153],{"class":3949},[3772,11654,5166],{"class":3945},[3772,11656,11657,11659,11661,11664],{"class":3774,"line":5527},[3772,11658,6598],{"class":3949},[3772,11660,4059],{"class":3945},[3772,11662,11663],{"class":3949},"list",[3772,11665,8709],{"class":3945},[3772,11667,11668],{"class":3774,"line":5533},[3772,11669,6621],{"class":3945},[3772,11671,11672],{"class":3774,"line":5539},[3772,11673,3965],{"emptyLinePlaceholder":3964},[3772,11675,11676],{"class":3774,"line":5545},[3772,11677,11678],{"class":3934},"        \u002F\u002F Редюсер з функцією попередньої підготовки (prepare)\n",[3772,11680,11681,11683],{"class":3774,"line":5550},[3772,11682,8785],{"class":3949},[3772,11684,4002],{"class":3945},[3772,11686,11687,11689,11691,11693,11695,11697,11699,11701,11703,11705],{"class":3774,"line":6121},[3772,11688,8792],{"class":3778},[3772,11690,5150],{"class":3945},[3772,11692,5153],{"class":3949},[3772,11694,3847],{"class":3945},[3772,11696,5163],{"class":3949},[3772,11698,4800],{"class":3945},[3772,11700,6361],{"class":4042},[3772,11702,4051],{"class":3945},[3772,11704,11572],{"class":4042},[3772,11706,6588],{"class":3945},[3772,11708,11709,11711,11713,11715,11717,11719,11721,11723,11725,11727],{"class":3774,"line":6131},[3772,11710,8815],{"class":3949},[3772,11712,4059],{"class":3945},[3772,11714,11663],{"class":3949},[3772,11716,4059],{"class":3945},[3772,11718,8757],{"class":3778},[3772,11720,5150],{"class":3945},[3772,11722,5163],{"class":3949},[3772,11724,4059],{"class":3945},[3772,11726,5059],{"class":3949},[3772,11728,5345],{"class":3945},[3772,11730,11731],{"class":3774,"line":6136},[3772,11732,8838],{"class":3945},[3772,11734,11735,11737,11739,11741,11743,11745],{"class":3774,"line":6142},[3772,11736,8844],{"class":3778},[3772,11738,5150],{"class":3945},[3772,11740,7131],{"class":3949},[3772,11742,4800],{"class":3945},[3772,11744,6459],{"class":4042},[3772,11746,5166],{"class":3945},[3772,11748,11749,11751],{"class":3774,"line":6150},[3772,11750,8868],{"class":3941},[3772,11752,4002],{"class":3945},[3772,11754,11755,11757],{"class":3774,"line":6157},[3772,11756,8876],{"class":3949},[3772,11758,4002],{"class":3945},[3772,11760,11761,11763,11765],{"class":3774,"line":6162},[3772,11762,8884],{"class":3949},[3772,11764,7171],{"class":3778},[3772,11766,10241],{"class":3945},[3772,11768,11769,11771],{"class":3774,"line":6629},[3772,11770,8897],{"class":3949},[3772,11772,4806],{"class":3945},[3772,11774,11775,11778,11780,11782,11784,11786],{"class":3774,"line":6653},[3772,11776,11777],{"class":3949},"                        createdAt:",[3772,11779,7199],{"class":3980},[3772,11781,7202],{"class":3778},[3772,11783,7205],{"class":3945},[3772,11785,7208],{"class":3778},[3772,11787,10241],{"class":3945},[3772,11789,11790],{"class":3774,"line":6698},[3772,11791,8925],{"class":3945},[3772,11793,11794],{"class":3774,"line":6703},[3772,11795,8931],{"class":3945},[3772,11797,11798],{"class":3774,"line":6709},[3772,11799,8838],{"class":3945},[3772,11801,11802],{"class":3774,"line":6734},[3772,11803,6621],{"class":3945},[3772,11805,11806],{"class":3774,"line":6753},[3772,11807,4014],{"class":3945},[3772,11809,11810],{"class":3774,"line":6758},[3772,11811,4020],{"class":3945},[3772,11813,11814],{"class":3774,"line":6763},[3772,11815,3965],{"emptyLinePlaceholder":3964},[3772,11817,11818,11820,11822,11824,11827,11829,11831,11833,11835,11837],{"class":3774,"line":6768},[3772,11819,3977],{"class":3941},[3772,11821,3981],{"class":3980},[3772,11823,3946],{"class":3945},[3772,11825,11826],{"class":3984},"clearAllTrips",[3772,11828,3847],{"class":3945},[3772,11830,9371],{"class":3984},[3772,11832,6801],{"class":3945},[3772,11834,6804],{"class":3949},[3772,11836,4059],{"class":3945},[3772,11838,6809],{"class":3949},[3772,11840,11841,11843,11845,11847,11849],{"class":3774,"line":6773},[3772,11842,3977],{"class":3941},[3772,11844,4196],{"class":3941},[3772,11846,6529],{"class":3949},[3772,11848,4059],{"class":3945},[3772,11850,6834],{"class":3949},[7025,11852,11854,11855,11857],{"id":11853},"обробка-зовнішніх-дій-через-extrareducers-детальний-розбір","Обробка зовнішніх дій через ",[3769,11856,8393],{},": Детальний розбір",[3743,11859,11860,11864,11865,11867,11868,11871,11872,11874],{},[3829,11861,11862],{},[3769,11863,8393],{}," — це спеціальна секція в ",[3769,11866,3846],{},", яка дозволяє обробляти дії, ",[3829,11869,11870],{},"створені поза межами поточного slice",". Це критична функція для роботи з асинхронними thunk-ами (",[3769,11873,3853],{},") або діями з інших slices.",[5075,11876,11877,11884,11909,11916],{},[3743,11878,11879],{},[3829,11880,11881,11882,4094],{},"Коли використовувати ",[3769,11883,8393],{},[4588,11885,11886,11892,11903],{},[3836,11887,11888,11889,11891],{},"✅ Обробка асинхронних дій з ",[3769,11890,3853],{}," (pending\u002Ffulfilled\u002Frejected)",[3836,11893,11894,11895,8279,11898,11900,11901,4669],{},"✅ Реагування на дії з інших slices (наприклад, ",[3769,11896,11897],{},"logout",[3769,11899,8419],{}," має очистити дані в ",[3769,11902,6804],{},[3836,11904,11905,11906,11908],{},"✅ Обробка дій, створених через ",[3769,11907,7031],{}," окремо",[3743,11910,11911],{},[3829,11912,11913,11914,4094],{},"Коли НЕ потрібен ",[3769,11915,8393],{},[3833,11917,11918],{},[3836,11919,11920,11921,11924,11925],{},"❌ Для дій, які належать ",[3829,11922,11923],{},"поточному slice"," — використовуйте звичайний ",[3769,11926,8385],{},[9418,11928,11930,11931,11933],{"id":11929},"формат-запису-extrareducers-builder-callback-pattern","Формат запису ",[3769,11932,8393],{},": Builder Callback Pattern",[3743,11935,11936,11937,11940],{},"Redux Toolkit рекомендує використовувати ",[3829,11938,11939],{},"builder callback notation"," замість об'єктного синтаксису:",[3762,11942,11944],{"className":3925,"code":11943,"language":3927,"meta":3767,"style":3767},"import { createSlice, PayloadAction } from '@reduxjs\u002Ftoolkit'\nimport { fetchTripsThunk, createTripThunk } from '..\u002Fthunks\u002FtripsThunks'\nimport { logout } from '.\u002FuserSlice' \u002F\u002F Дія з іншого slice!\n\nexport const tripsSlice = createSlice({\n    name: 'trips',\n    initialState,\n    reducers: {\n        \u002F\u002F Власні дії slice\n        clearTrips(state) {\n            state.items = []\n        },\n    },\n    extraReducers: (builder) => {\n        \u002F\u002F Builder має 3 методи:\n        \u002F\u002F - addCase: обробка конкретної дії\n        \u002F\u002F - addMatcher: обробка групи дій за умовою\n        \u002F\u002F - addDefaultCase: обробка всіх неопрацьованих дій\n\n        builder\n            \u002F\u002F 1. ОБРОБКА КОНКРЕТНОЇ ДІЇ (addCase)\n            .addCase(fetchTripsThunk.pending, (state) => {\n                state.loading = true\n                state.error = null\n            })\n            .addCase(fetchTripsThunk.fulfilled, (state, action: PayloadAction\u003CTrip[]>) => {\n                state.loading = false\n                state.items = action.payload \u002F\u002F Дані прийшли з сервера\n            })\n            .addCase(fetchTripsThunk.rejected, (state, action) => {\n                state.loading = false\n                state.error = action.payload ?? 'Помилка завантаження'\n            })\n\n            \u002F\u002F 2. РЕАГУВАННЯ НА ДІЇ З ІНШОГО SLICE\n            .addCase(logout, (state) => {\n                \u002F\u002F Коли користувач виходить — очищаємо поїздки\n                state.items = []\n                state.loading = false\n                state.error = null\n            })\n    },\n})\n",[3769,11945,11946,11964,11984,12002,12006,12020,12028,12034,12040,12045,12055,12065,12069,12073,12089,12094,12099,12104,12109,12113,12117,12122,12146,12158,12170,12174,12211,12223,12242,12246,12275,12287,12309,12313,12317,12322,12342,12347,12357,12369,12381,12385,12389],{"__ignoreMap":3767},[3772,11947,11948,11950,11952,11954,11956,11958,11960,11962],{"class":3774,"line":3775},[3772,11949,3942],{"class":3941},[3772,11951,3946],{"class":3945},[3772,11953,3846],{"class":3949},[3772,11955,3847],{"class":3945},[3772,11957,6361],{"class":3949},[3772,11959,3952],{"class":3945},[3772,11961,3955],{"class":3941},[3772,11963,3958],{"class":3781},[3772,11965,11966,11968,11970,11972,11974,11977,11979,11981],{"class":3774,"line":3938},[3772,11967,3942],{"class":3941},[3772,11969,3946],{"class":3945},[3772,11971,9229],{"class":3949},[3772,11973,3847],{"class":3945},[3772,11975,11976],{"class":3949},"createTripThunk",[3772,11978,3952],{"class":3945},[3772,11980,3955],{"class":3941},[3772,11982,11983],{"class":3781}," '..\u002Fthunks\u002FtripsThunks'\n",[3772,11985,11986,11988,11990,11992,11994,11996,11999],{"class":3774,"line":3961},[3772,11987,3942],{"class":3941},[3772,11989,3946],{"class":3945},[3772,11991,11897],{"class":3949},[3772,11993,3952],{"class":3945},[3772,11995,3955],{"class":3941},[3772,11997,11998],{"class":3781}," '.\u002FuserSlice'",[3772,12000,12001],{"class":3934}," \u002F\u002F Дія з іншого slice!\n",[3772,12003,12004],{"class":3774,"line":3968},[3772,12005,3965],{"emptyLinePlaceholder":3964},[3772,12007,12008,12010,12012,12014,12016,12018],{"class":3774,"line":3974},[3772,12009,3977],{"class":3941},[3772,12011,3981],{"class":3980},[3772,12013,6529],{"class":3984},[3772,12015,3988],{"class":3945},[3772,12017,3846],{"class":3778},[3772,12019,3993],{"class":3945},[3772,12021,12022,12024,12026],{"class":3774,"line":3996},[3772,12023,6540],{"class":3949},[3772,12025,6543],{"class":3781},[3772,12027,4806],{"class":3945},[3772,12029,12030,12032],{"class":3774,"line":4005},[3772,12031,6550],{"class":3949},[3772,12033,4806],{"class":3945},[3772,12035,12036,12038],{"class":3774,"line":4011},[3772,12037,6557],{"class":3949},[3772,12039,4002],{"class":3945},[3772,12041,12042],{"class":3774,"line":4017},[3772,12043,12044],{"class":3934},"        \u002F\u002F Власні дії slice\n",[3772,12046,12047,12049,12051,12053],{"class":3774,"line":4023},[3772,12048,8692],{"class":3778},[3772,12050,5150],{"class":3945},[3772,12052,5153],{"class":3949},[3772,12054,5166],{"class":3945},[3772,12056,12057,12059,12061,12063],{"class":3774,"line":4028},[3772,12058,6598],{"class":3949},[3772,12060,4059],{"class":3945},[3772,12062,5237],{"class":3949},[3772,12064,8709],{"class":3945},[3772,12066,12067],{"class":3774,"line":4034},[3772,12068,6621],{"class":3945},[3772,12070,12071],{"class":3774,"line":4068},[3772,12072,4014],{"class":3945},[3772,12074,12075,12077,12079,12081,12083,12085,12087],{"class":3774,"line":4313},[3772,12076,9190],{"class":3778},[3772,12078,4094],{"class":3949},[3772,12080,5179],{"class":3945},[3772,12082,9197],{"class":3949},[3772,12084,5765],{"class":3945},[3772,12086,5768],{"class":3980},[3772,12088,4002],{"class":3945},[3772,12090,12091],{"class":3774,"line":4470},[3772,12092,12093],{"class":3934},"        \u002F\u002F Builder має 3 методи:\n",[3772,12095,12096],{"class":3774,"line":4879},[3772,12097,12098],{"class":3934},"        \u002F\u002F - addCase: обробка конкретної дії\n",[3772,12100,12101],{"class":3774,"line":4892},[3772,12102,12103],{"class":3934},"        \u002F\u002F - addMatcher: обробка групи дій за умовою\n",[3772,12105,12106],{"class":3774,"line":4903},[3772,12107,12108],{"class":3934},"        \u002F\u002F - addDefaultCase: обробка всіх неопрацьованих дій\n",[3772,12110,12111],{"class":3774,"line":4909},[3772,12112,3965],{"emptyLinePlaceholder":3964},[3772,12114,12115],{"class":3774,"line":5521},[3772,12116,9215],{"class":3949},[3772,12118,12119],{"class":3774,"line":5527},[3772,12120,12121],{"class":3934},"            \u002F\u002F 1. ОБРОБКА КОНКРЕТНОЇ ДІЇ (addCase)\n",[3772,12123,12124,12126,12128,12130,12132,12134,12136,12138,12140,12142,12144],{"class":3774,"line":5533},[3772,12125,9221],{"class":3945},[3772,12127,9224],{"class":3778},[3772,12129,5150],{"class":3945},[3772,12131,9229],{"class":3949},[3772,12133,4059],{"class":3945},[3772,12135,9234],{"class":3949},[3772,12137,7128],{"class":3945},[3772,12139,5153],{"class":3949},[3772,12141,5765],{"class":3945},[3772,12143,5768],{"class":3980},[3772,12145,4002],{"class":3945},[3772,12147,12148,12150,12152,12154,12156],{"class":3774,"line":5539},[3772,12149,8815],{"class":3949},[3772,12151,4059],{"class":3945},[3772,12153,6741],{"class":3949},[3772,12155,3988],{"class":3945},[3772,12157,4865],{"class":3980},[3772,12159,12160,12162,12164,12166,12168],{"class":3774,"line":5545},[3772,12161,8815],{"class":3949},[3772,12163,4059],{"class":3945},[3772,12165,5072],{"class":3949},[3772,12167,3988],{"class":3945},[3772,12169,4816],{"class":3980},[3772,12171,12172],{"class":3774,"line":5550},[3772,12173,9263],{"class":3945},[3772,12175,12176,12178,12180,12182,12184,12186,12188,12190,12192,12194,12196,12198,12200,12202,12204,12207,12209],{"class":3774,"line":6121},[3772,12177,9221],{"class":3945},[3772,12179,9224],{"class":3778},[3772,12181,5150],{"class":3945},[3772,12183,9229],{"class":3949},[3772,12185,4059],{"class":3945},[3772,12187,9279],{"class":3949},[3772,12189,7128],{"class":3945},[3772,12191,5153],{"class":3949},[3772,12193,3847],{"class":3945},[3772,12195,5163],{"class":3949},[3772,12197,4800],{"class":3945},[3772,12199,6361],{"class":4042},[3772,12201,4051],{"class":3945},[3772,12203,6436],{"class":4042},[3772,12205,12206],{"class":3945},"[]>) ",[3772,12208,5768],{"class":3980},[3772,12210,4002],{"class":3945},[3772,12212,12213,12215,12217,12219,12221],{"class":3774,"line":6131},[3772,12214,8815],{"class":3949},[3772,12216,4059],{"class":3945},[3772,12218,6741],{"class":3949},[3772,12220,3988],{"class":3945},[3772,12222,9324],{"class":3980},[3772,12224,12225,12227,12229,12231,12233,12235,12237,12239],{"class":3774,"line":6136},[3772,12226,8815],{"class":3949},[3772,12228,4059],{"class":3945},[3772,12230,5237],{"class":3949},[3772,12232,3988],{"class":3945},[3772,12234,5163],{"class":3949},[3772,12236,4059],{"class":3945},[3772,12238,5059],{"class":3949},[3772,12240,12241],{"class":3934}," \u002F\u002F Дані прийшли з сервера\n",[3772,12243,12244],{"class":3774,"line":6142},[3772,12245,9263],{"class":3945},[3772,12247,12248,12250,12252,12254,12256,12258,12261,12263,12265,12267,12269,12271,12273],{"class":3774,"line":6150},[3772,12249,9221],{"class":3945},[3772,12251,9224],{"class":3778},[3772,12253,5150],{"class":3945},[3772,12255,9229],{"class":3949},[3772,12257,4059],{"class":3945},[3772,12259,12260],{"class":3949},"rejected",[3772,12262,7128],{"class":3945},[3772,12264,5153],{"class":3949},[3772,12266,3847],{"class":3945},[3772,12268,5163],{"class":3949},[3772,12270,5765],{"class":3945},[3772,12272,5768],{"class":3980},[3772,12274,4002],{"class":3945},[3772,12276,12277,12279,12281,12283,12285],{"class":3774,"line":6157},[3772,12278,8815],{"class":3949},[3772,12280,4059],{"class":3945},[3772,12282,6741],{"class":3949},[3772,12284,3988],{"class":3945},[3772,12286,9324],{"class":3980},[3772,12288,12289,12291,12293,12295,12297,12299,12301,12303,12306],{"class":3774,"line":6162},[3772,12290,8815],{"class":3949},[3772,12292,4059],{"class":3945},[3772,12294,5072],{"class":3949},[3772,12296,3988],{"class":3945},[3772,12298,5163],{"class":3949},[3772,12300,4059],{"class":3945},[3772,12302,5059],{"class":3949},[3772,12304,12305],{"class":3945}," ?? ",[3772,12307,12308],{"class":3781},"'Помилка завантаження'\n",[3772,12310,12311],{"class":3774,"line":6629},[3772,12312,9263],{"class":3945},[3772,12314,12315],{"class":3774,"line":6653},[3772,12316,3965],{"emptyLinePlaceholder":3964},[3772,12318,12319],{"class":3774,"line":6698},[3772,12320,12321],{"class":3934},"            \u002F\u002F 2. РЕАГУВАННЯ НА ДІЇ З ІНШОГО SLICE\n",[3772,12323,12324,12326,12328,12330,12332,12334,12336,12338,12340],{"class":3774,"line":6703},[3772,12325,9221],{"class":3945},[3772,12327,9224],{"class":3778},[3772,12329,5150],{"class":3945},[3772,12331,11897],{"class":3949},[3772,12333,7128],{"class":3945},[3772,12335,5153],{"class":3949},[3772,12337,5765],{"class":3945},[3772,12339,5768],{"class":3980},[3772,12341,4002],{"class":3945},[3772,12343,12344],{"class":3774,"line":6709},[3772,12345,12346],{"class":3934},"                \u002F\u002F Коли користувач виходить — очищаємо поїздки\n",[3772,12348,12349,12351,12353,12355],{"class":3774,"line":6734},[3772,12350,8815],{"class":3949},[3772,12352,4059],{"class":3945},[3772,12354,5237],{"class":3949},[3772,12356,8709],{"class":3945},[3772,12358,12359,12361,12363,12365,12367],{"class":3774,"line":6753},[3772,12360,8815],{"class":3949},[3772,12362,4059],{"class":3945},[3772,12364,6741],{"class":3949},[3772,12366,3988],{"class":3945},[3772,12368,9324],{"class":3980},[3772,12370,12371,12373,12375,12377,12379],{"class":3774,"line":6758},[3772,12372,8815],{"class":3949},[3772,12374,4059],{"class":3945},[3772,12376,5072],{"class":3949},[3772,12378,3988],{"class":3945},[3772,12380,4816],{"class":3980},[3772,12382,12383],{"class":3774,"line":6763},[3772,12384,9263],{"class":3945},[3772,12386,12387],{"class":3774,"line":6768},[3772,12388,4014],{"class":3945},[3772,12390,12391],{"class":3774,"line":6773},[3772,12392,4020],{"class":3945},[3875,12394,12395,12404],{},[3743,12396,12397],{},[3829,12398,12399,12400,3869,12402,4094],{},"Різниця між ",[3769,12401,8385],{},[3769,12403,8393],{},[12405,12406,12407,12425],"table",{},[12408,12409,12410],"thead",{},[12411,12412,12413,12417,12421],"tr",{},[12414,12415,12416],"th",{},"Властивість",[12414,12418,12419],{},[3769,12420,8385],{},[12414,12422,12423],{},[3769,12424,8393],{},[12426,12427,12428,12442,12455,12468],"tbody",{},[12411,12429,12430,12436,12439],{},[12431,12432,12433],"td",{},[3829,12434,12435],{},"Власність slice",[12431,12437,12438],{},"✅ Дії належать цьому slice",[12431,12440,12441],{},"❌ Дії створені ззовні",[12411,12443,12444,12449,12452],{},[12431,12445,12446],{},[3829,12447,12448],{},"Автоматична генерація action creators",[12431,12450,12451],{},"✅ Генеруються автоматично",[12431,12453,12454],{},"❌ Потрібно імпортувати окремо",[12411,12456,12457,12462,12465],{},[12431,12458,12459],{},[3829,12460,12461],{},"Використання",[12431,12463,12464],{},"Внутрішня логіка slice",[12431,12466,12467],{},"Асинхронні дії, міжслайсова логіка",[12411,12469,12470,12475,12481],{},[12431,12471,12472],{},[3829,12473,12474],{},"Приклад",[12431,12476,12477,3847,12479],{},[3769,12478,6788],{},[3769,12480,6793],{},[12431,12482,12483,3847,12486],{},[3769,12484,12485],{},"fetchTripsThunk.fulfilled",[3769,12487,11897],{},[9418,12489,12491,12492,12495],{"id":12490},"розширені-матчери-addmatcher-обєднання-груп-дій","Розширені матчери (",[3769,12493,12494],{},"addMatcher","): Об'єднання груп дій",[3743,12497,12498,12499,3847,12502,3847,12505,3847,12508,3847,12511,12514],{},"У великих мобільних застосунках часто потрібно показувати єдиний індикатор завантаження або централізовано очищувати помилки при запуску будь-якого з десятка асинхронних запитів. Утиліти ",[3769,12500,12501],{},"isAnyOf",[3769,12503,12504],{},"isAllOf",[3769,12506,12507],{},"isPending",[3769,12509,12510],{},"isFulfilled",[3769,12512,12513],{},"isRejected"," дозволяють елегантно скоротити код:",[3762,12516,12518],{"className":3925,"code":12517,"language":3927,"meta":3767,"style":3767},"import { createSlice, isAnyOf, isPending, isFulfilled, isRejected } from '@reduxjs\u002Ftoolkit'\nimport { resetAllFilters } from '.\u002FfiltersActions'\nimport { fetchTripsThunk, createTripThunk, deleteTripThunk, updateTripThunk } from '.\u002FtripsThunks'\n\nexport const tripsSlice = createSlice({\n    name: 'trips',\n    initialState,\n    reducers: {},\n    extraReducers: (builder) => {\n        builder\n            \u002F\u002F 1. ТОЧНА ОБРОБКА конкретних успішних дій\n            .addCase(fetchTripsThunk.fulfilled, (state, action) => {\n                state.items = action.payload\n            })\n            .addCase(createTripThunk.fulfilled, (state, action) => {\n                state.items.unshift(action.payload) \u002F\u002F Додаємо на початок\n            })\n            .addCase(deleteTripThunk.fulfilled, (state, action) => {\n                state.items = state.items.filter((t) => t.id !== action.payload)\n            })\n\n            \u002F\u002F 2. РЕАГУВАННЯ НА ДІЮ З ІНШОГО SLICE\n            .addCase(resetAllFilters, (state) => {\n                state.items = []\n            })\n\n            \u002F\u002F 3. МАТЧЕР: Об'єднання ВСІХ станів завантаження (pending)\n            \u002F\u002F Замість копіювання коду для кожного thunk окремо!\n            .addMatcher(\n                isAnyOf(\n                    fetchTripsThunk.pending,\n                    createTripThunk.pending,\n                    deleteTripThunk.pending,\n                    updateTripThunk.pending,\n                ),\n                (state) => {\n                    state.loading = true\n                    state.error = null\n                },\n            )\n\n            \u002F\u002F 4. МАТЧЕР: Загальне завершення операцій (fulfilled)\n            .addMatcher(\n                isAnyOf(\n                    fetchTripsThunk.fulfilled,\n                    createTripThunk.fulfilled,\n                    deleteTripThunk.fulfilled,\n                    updateTripThunk.fulfilled,\n                ),\n                (state) => {\n                    state.loading = false\n                },\n            )\n\n            \u002F\u002F 5. МАТЧЕР: Універсальне перехоплення ВСІХ помилок (rejected)\n            .addMatcher(\n                isAnyOf(\n                    fetchTripsThunk.rejected,\n                    createTripThunk.rejected,\n                    deleteTripThunk.rejected,\n                    updateTripThunk.rejected,\n                ),\n                (state, action) => {\n                    state.loading = false\n                    state.error = (action.payload as string) ?? action.error.message ?? 'Невідома помилка'\n                },\n            )\n    },\n})\n",[3769,12519,12520,12550,12565,12594,12598,12612,12620,12626,12633,12649,12653,12658,12686,12702,12706,12734,12759,12763,12791,12835,12839,12843,12848,12868,12878,12882,12886,12891,12896,12905,12912,12923,12934,12945,12956,12961,12974,12987,12999,13004,13009,13013,13018,13026,13032,13042,13052,13062,13072,13076,13088,13100,13104,13108,13112,13117,13125,13131,13141,13151,13161,13171,13175,13191,13203,13243,13247,13251,13255],{"__ignoreMap":3767},[3772,12521,12522,12524,12526,12528,12530,12532,12534,12536,12538,12540,12542,12544,12546,12548],{"class":3774,"line":3775},[3772,12523,3942],{"class":3941},[3772,12525,3946],{"class":3945},[3772,12527,3846],{"class":3949},[3772,12529,3847],{"class":3945},[3772,12531,12501],{"class":3949},[3772,12533,3847],{"class":3945},[3772,12535,12507],{"class":3949},[3772,12537,3847],{"class":3945},[3772,12539,12510],{"class":3949},[3772,12541,3847],{"class":3945},[3772,12543,12513],{"class":3949},[3772,12545,3952],{"class":3945},[3772,12547,3955],{"class":3941},[3772,12549,3958],{"class":3781},[3772,12551,12552,12554,12556,12558,12560,12562],{"class":3774,"line":3938},[3772,12553,3942],{"class":3941},[3772,12555,3946],{"class":3945},[3772,12557,7374],{"class":3949},[3772,12559,3952],{"class":3945},[3772,12561,3955],{"class":3941},[3772,12563,12564],{"class":3781}," '.\u002FfiltersActions'\n",[3772,12566,12567,12569,12571,12573,12575,12577,12579,12582,12584,12587,12589,12591],{"class":3774,"line":3961},[3772,12568,3942],{"class":3941},[3772,12570,3946],{"class":3945},[3772,12572,9229],{"class":3949},[3772,12574,3847],{"class":3945},[3772,12576,11976],{"class":3949},[3772,12578,3847],{"class":3945},[3772,12580,12581],{"class":3949},"deleteTripThunk",[3772,12583,3847],{"class":3945},[3772,12585,12586],{"class":3949},"updateTripThunk",[3772,12588,3952],{"class":3945},[3772,12590,3955],{"class":3941},[3772,12592,12593],{"class":3781}," '.\u002FtripsThunks'\n",[3772,12595,12596],{"class":3774,"line":3968},[3772,12597,3965],{"emptyLinePlaceholder":3964},[3772,12599,12600,12602,12604,12606,12608,12610],{"class":3774,"line":3974},[3772,12601,3977],{"class":3941},[3772,12603,3981],{"class":3980},[3772,12605,6529],{"class":3984},[3772,12607,3988],{"class":3945},[3772,12609,3846],{"class":3778},[3772,12611,3993],{"class":3945},[3772,12613,12614,12616,12618],{"class":3774,"line":3996},[3772,12615,6540],{"class":3949},[3772,12617,6543],{"class":3781},[3772,12619,4806],{"class":3945},[3772,12621,12622,12624],{"class":3774,"line":4005},[3772,12623,6550],{"class":3949},[3772,12625,4806],{"class":3945},[3772,12627,12628,12630],{"class":3774,"line":4011},[3772,12629,6557],{"class":3949},[3772,12631,12632],{"class":3945}," {},\n",[3772,12634,12635,12637,12639,12641,12643,12645,12647],{"class":3774,"line":4017},[3772,12636,9190],{"class":3778},[3772,12638,4094],{"class":3949},[3772,12640,5179],{"class":3945},[3772,12642,9197],{"class":3949},[3772,12644,5765],{"class":3945},[3772,12646,5768],{"class":3980},[3772,12648,4002],{"class":3945},[3772,12650,12651],{"class":3774,"line":4023},[3772,12652,9215],{"class":3949},[3772,12654,12655],{"class":3774,"line":4028},[3772,12656,12657],{"class":3934},"            \u002F\u002F 1. ТОЧНА ОБРОБКА конкретних успішних дій\n",[3772,12659,12660,12662,12664,12666,12668,12670,12672,12674,12676,12678,12680,12682,12684],{"class":3774,"line":4034},[3772,12661,9221],{"class":3945},[3772,12663,9224],{"class":3778},[3772,12665,5150],{"class":3945},[3772,12667,9229],{"class":3949},[3772,12669,4059],{"class":3945},[3772,12671,9279],{"class":3949},[3772,12673,7128],{"class":3945},[3772,12675,5153],{"class":3949},[3772,12677,3847],{"class":3945},[3772,12679,5163],{"class":3949},[3772,12681,5765],{"class":3945},[3772,12683,5768],{"class":3980},[3772,12685,4002],{"class":3945},[3772,12687,12688,12690,12692,12694,12696,12698,12700],{"class":3774,"line":4068},[3772,12689,8815],{"class":3949},[3772,12691,4059],{"class":3945},[3772,12693,5237],{"class":3949},[3772,12695,3988],{"class":3945},[3772,12697,5163],{"class":3949},[3772,12699,4059],{"class":3945},[3772,12701,6750],{"class":3949},[3772,12703,12704],{"class":3774,"line":4313},[3772,12705,9263],{"class":3945},[3772,12707,12708,12710,12712,12714,12716,12718,12720,12722,12724,12726,12728,12730,12732],{"class":3774,"line":4470},[3772,12709,9221],{"class":3945},[3772,12711,9224],{"class":3778},[3772,12713,5150],{"class":3945},[3772,12715,11976],{"class":3949},[3772,12717,4059],{"class":3945},[3772,12719,9279],{"class":3949},[3772,12721,7128],{"class":3945},[3772,12723,5153],{"class":3949},[3772,12725,3847],{"class":3945},[3772,12727,5163],{"class":3949},[3772,12729,5765],{"class":3945},[3772,12731,5768],{"class":3980},[3772,12733,4002],{"class":3945},[3772,12735,12736,12738,12740,12742,12744,12746,12748,12750,12752,12754,12756],{"class":3774,"line":4879},[3772,12737,8815],{"class":3949},[3772,12739,4059],{"class":3945},[3772,12741,5237],{"class":3949},[3772,12743,4059],{"class":3945},[3772,12745,8757],{"class":3778},[3772,12747,5150],{"class":3945},[3772,12749,5163],{"class":3949},[3772,12751,4059],{"class":3945},[3772,12753,5059],{"class":3949},[3772,12755,5765],{"class":3945},[3772,12757,12758],{"class":3934},"\u002F\u002F Додаємо на початок\n",[3772,12760,12761],{"class":3774,"line":4892},[3772,12762,9263],{"class":3945},[3772,12764,12765,12767,12769,12771,12773,12775,12777,12779,12781,12783,12785,12787,12789],{"class":3774,"line":4903},[3772,12766,9221],{"class":3945},[3772,12768,9224],{"class":3778},[3772,12770,5150],{"class":3945},[3772,12772,12581],{"class":3949},[3772,12774,4059],{"class":3945},[3772,12776,9279],{"class":3949},[3772,12778,7128],{"class":3945},[3772,12780,5153],{"class":3949},[3772,12782,3847],{"class":3945},[3772,12784,5163],{"class":3949},[3772,12786,5765],{"class":3945},[3772,12788,5768],{"class":3980},[3772,12790,4002],{"class":3945},[3772,12792,12793,12795,12797,12799,12801,12803,12805,12807,12809,12811,12813,12815,12817,12819,12821,12823,12825,12827,12829,12831,12833],{"class":3774,"line":4909},[3772,12794,8815],{"class":3949},[3772,12796,4059],{"class":3945},[3772,12798,5237],{"class":3949},[3772,12800,3988],{"class":3945},[3772,12802,5153],{"class":3949},[3772,12804,4059],{"class":3945},[3772,12806,5237],{"class":3949},[3772,12808,4059],{"class":3945},[3772,12810,6053],{"class":3778},[3772,12812,6056],{"class":3945},[3772,12814,6059],{"class":3949},[3772,12816,5765],{"class":3945},[3772,12818,5768],{"class":3980},[3772,12820,6066],{"class":3949},[3772,12822,4059],{"class":3945},[3772,12824,5812],{"class":3949},[3772,12826,6073],{"class":3945},[3772,12828,5163],{"class":3949},[3772,12830,4059],{"class":3945},[3772,12832,5059],{"class":3949},[3772,12834,5345],{"class":3945},[3772,12836,12837],{"class":3774,"line":5521},[3772,12838,9263],{"class":3945},[3772,12840,12841],{"class":3774,"line":5527},[3772,12842,3965],{"emptyLinePlaceholder":3964},[3772,12844,12845],{"class":3774,"line":5533},[3772,12846,12847],{"class":3934},"            \u002F\u002F 2. РЕАГУВАННЯ НА ДІЮ З ІНШОГО SLICE\n",[3772,12849,12850,12852,12854,12856,12858,12860,12862,12864,12866],{"class":3774,"line":5539},[3772,12851,9221],{"class":3945},[3772,12853,9224],{"class":3778},[3772,12855,5150],{"class":3945},[3772,12857,7374],{"class":3949},[3772,12859,7128],{"class":3945},[3772,12861,5153],{"class":3949},[3772,12863,5765],{"class":3945},[3772,12865,5768],{"class":3980},[3772,12867,4002],{"class":3945},[3772,12869,12870,12872,12874,12876],{"class":3774,"line":5545},[3772,12871,8815],{"class":3949},[3772,12873,4059],{"class":3945},[3772,12875,5237],{"class":3949},[3772,12877,8709],{"class":3945},[3772,12879,12880],{"class":3774,"line":5550},[3772,12881,9263],{"class":3945},[3772,12883,12884],{"class":3774,"line":6121},[3772,12885,3965],{"emptyLinePlaceholder":3964},[3772,12887,12888],{"class":3774,"line":6131},[3772,12889,12890],{"class":3934},"            \u002F\u002F 3. МАТЧЕР: Об'єднання ВСІХ станів завантаження (pending)\n",[3772,12892,12893],{"class":3774,"line":6136},[3772,12894,12895],{"class":3934},"            \u002F\u002F Замість копіювання коду для кожного thunk окремо!\n",[3772,12897,12898,12900,12902],{"class":3774,"line":6142},[3772,12899,9221],{"class":3945},[3772,12901,12494],{"class":3778},[3772,12903,12904],{"class":3945},"(\n",[3772,12906,12907,12910],{"class":3774,"line":6150},[3772,12908,12909],{"class":3778},"                isAnyOf",[3772,12911,12904],{"class":3945},[3772,12913,12914,12917,12919,12921],{"class":3774,"line":6157},[3772,12915,12916],{"class":3949},"                    fetchTripsThunk",[3772,12918,4059],{"class":3945},[3772,12920,9234],{"class":3949},[3772,12922,4806],{"class":3945},[3772,12924,12925,12928,12930,12932],{"class":3774,"line":6162},[3772,12926,12927],{"class":3949},"                    createTripThunk",[3772,12929,4059],{"class":3945},[3772,12931,9234],{"class":3949},[3772,12933,4806],{"class":3945},[3772,12935,12936,12939,12941,12943],{"class":3774,"line":6629},[3772,12937,12938],{"class":3949},"                    deleteTripThunk",[3772,12940,4059],{"class":3945},[3772,12942,9234],{"class":3949},[3772,12944,4806],{"class":3945},[3772,12946,12947,12950,12952,12954],{"class":3774,"line":6653},[3772,12948,12949],{"class":3949},"                    updateTripThunk",[3772,12951,4059],{"class":3945},[3772,12953,9234],{"class":3949},[3772,12955,4806],{"class":3945},[3772,12957,12958],{"class":3774,"line":6698},[3772,12959,12960],{"class":3945},"                ),\n",[3772,12962,12963,12966,12968,12970,12972],{"class":3774,"line":6703},[3772,12964,12965],{"class":3945},"                (",[3772,12967,5153],{"class":3949},[3772,12969,5765],{"class":3945},[3772,12971,5768],{"class":3980},[3772,12973,4002],{"class":3945},[3772,12975,12976,12979,12981,12983,12985],{"class":3774,"line":6709},[3772,12977,12978],{"class":3949},"                    state",[3772,12980,4059],{"class":3945},[3772,12982,6741],{"class":3949},[3772,12984,3988],{"class":3945},[3772,12986,4865],{"class":3980},[3772,12988,12989,12991,12993,12995,12997],{"class":3774,"line":6734},[3772,12990,12978],{"class":3949},[3772,12992,4059],{"class":3945},[3772,12994,5072],{"class":3949},[3772,12996,3988],{"class":3945},[3772,12998,4816],{"class":3980},[3772,13000,13001],{"class":3774,"line":6753},[3772,13002,13003],{"class":3945},"                },\n",[3772,13005,13006],{"class":3774,"line":6758},[3772,13007,13008],{"class":3945},"            )\n",[3772,13010,13011],{"class":3774,"line":6763},[3772,13012,3965],{"emptyLinePlaceholder":3964},[3772,13014,13015],{"class":3774,"line":6768},[3772,13016,13017],{"class":3934},"            \u002F\u002F 4. МАТЧЕР: Загальне завершення операцій (fulfilled)\n",[3772,13019,13020,13022,13024],{"class":3774,"line":6773},[3772,13021,9221],{"class":3945},[3772,13023,12494],{"class":3778},[3772,13025,12904],{"class":3945},[3772,13027,13028,13030],{"class":3774,"line":6779},[3772,13029,12909],{"class":3778},[3772,13031,12904],{"class":3945},[3772,13033,13034,13036,13038,13040],{"class":3774,"line":6812},[3772,13035,12916],{"class":3949},[3772,13037,4059],{"class":3945},[3772,13039,9279],{"class":3949},[3772,13041,4806],{"class":3945},[3772,13043,13044,13046,13048,13050],{"class":3774,"line":6817},[3772,13045,12927],{"class":3949},[3772,13047,4059],{"class":3945},[3772,13049,9279],{"class":3949},[3772,13051,4806],{"class":3945},[3772,13053,13054,13056,13058,13060],{"class":3774,"line":6823},[3772,13055,12938],{"class":3949},[3772,13057,4059],{"class":3945},[3772,13059,9279],{"class":3949},[3772,13061,4806],{"class":3945},[3772,13063,13064,13066,13068,13070],{"class":3774,"line":8841},[3772,13065,12949],{"class":3949},[3772,13067,4059],{"class":3945},[3772,13069,9279],{"class":3949},[3772,13071,4806],{"class":3945},[3772,13073,13074],{"class":3774,"line":8865},[3772,13075,12960],{"class":3945},[3772,13077,13078,13080,13082,13084,13086],{"class":3774,"line":8873},[3772,13079,12965],{"class":3945},[3772,13081,5153],{"class":3949},[3772,13083,5765],{"class":3945},[3772,13085,5768],{"class":3980},[3772,13087,4002],{"class":3945},[3772,13089,13090,13092,13094,13096,13098],{"class":3774,"line":8881},[3772,13091,12978],{"class":3949},[3772,13093,4059],{"class":3945},[3772,13095,6741],{"class":3949},[3772,13097,3988],{"class":3945},[3772,13099,9324],{"class":3980},[3772,13101,13102],{"class":3774,"line":8894},[3772,13103,13003],{"class":3945},[3772,13105,13106],{"class":3774,"line":8902},[3772,13107,13008],{"class":3945},[3772,13109,13110],{"class":3774,"line":8910},[3772,13111,3965],{"emptyLinePlaceholder":3964},[3772,13113,13114],{"class":3774,"line":8922},[3772,13115,13116],{"class":3934},"            \u002F\u002F 5. МАТЧЕР: Універсальне перехоплення ВСІХ помилок (rejected)\n",[3772,13118,13119,13121,13123],{"class":3774,"line":8928},[3772,13120,9221],{"class":3945},[3772,13122,12494],{"class":3778},[3772,13124,12904],{"class":3945},[3772,13126,13127,13129],{"class":3774,"line":8934},[3772,13128,12909],{"class":3778},[3772,13130,12904],{"class":3945},[3772,13132,13133,13135,13137,13139],{"class":3774,"line":8939},[3772,13134,12916],{"class":3949},[3772,13136,4059],{"class":3945},[3772,13138,12260],{"class":3949},[3772,13140,4806],{"class":3945},[3772,13142,13143,13145,13147,13149],{"class":3774,"line":8944},[3772,13144,12927],{"class":3949},[3772,13146,4059],{"class":3945},[3772,13148,12260],{"class":3949},[3772,13150,4806],{"class":3945},[3772,13152,13153,13155,13157,13159],{"class":3774,"line":8949},[3772,13154,12938],{"class":3949},[3772,13156,4059],{"class":3945},[3772,13158,12260],{"class":3949},[3772,13160,4806],{"class":3945},[3772,13162,13163,13165,13167,13169],{"class":3774,"line":8955},[3772,13164,12949],{"class":3949},[3772,13166,4059],{"class":3945},[3772,13168,12260],{"class":3949},[3772,13170,4806],{"class":3945},[3772,13172,13173],{"class":3774,"line":8992},[3772,13174,12960],{"class":3945},[3772,13176,13177,13179,13181,13183,13185,13187,13189],{"class":3774,"line":9040},[3772,13178,12965],{"class":3945},[3772,13180,5153],{"class":3949},[3772,13182,3847],{"class":3945},[3772,13184,5163],{"class":3949},[3772,13186,5765],{"class":3945},[3772,13188,5768],{"class":3980},[3772,13190,4002],{"class":3945},[3772,13192,13193,13195,13197,13199,13201],{"class":3774,"line":9052},[3772,13194,12978],{"class":3949},[3772,13196,4059],{"class":3945},[3772,13198,6741],{"class":3949},[3772,13200,3988],{"class":3945},[3772,13202,9324],{"class":3980},[3772,13204,13205,13207,13209,13211,13213,13215,13217,13219,13222,13224,13227,13229,13231,13233,13235,13238,13240],{"class":3774,"line":9077},[3772,13206,12978],{"class":3949},[3772,13208,4059],{"class":3945},[3772,13210,5072],{"class":3949},[3772,13212,5759],{"class":3945},[3772,13214,5163],{"class":3949},[3772,13216,4059],{"class":3945},[3772,13218,5059],{"class":3949},[3772,13220,13221],{"class":3941}," as",[3772,13223,7815],{"class":4042},[3772,13225,13226],{"class":3945},") ?? ",[3772,13228,5163],{"class":3949},[3772,13230,4059],{"class":3945},[3772,13232,5072],{"class":3949},[3772,13234,4059],{"class":3945},[3772,13236,13237],{"class":3949},"message",[3772,13239,12305],{"class":3945},[3772,13241,13242],{"class":3781},"'Невідома помилка'\n",[3772,13244,13245],{"class":3774,"line":9082},[3772,13246,13003],{"class":3945},[3772,13248,13249],{"class":3774,"line":9087},[3772,13250,13008],{"class":3945},[3772,13252,13253],{"class":3774,"line":9092},[3772,13254,4014],{"class":3945},[3772,13256,13257],{"class":3774,"line":9098},[3772,13258,4020],{"class":3945},[4474,13260,13261,13266,13269,13292,13304],{},[3743,13262,13263],{},[3829,13264,13265],{},"Порядок виконання має значення!",[3743,13267,13268],{},"Redux Toolkit виконує обробники у строгому порядку:",[4588,13270,13271,13278,13285],{},[3836,13272,13273,13274,13277],{},"Спочатку всі ",[3769,13275,13276],{},".addCase()"," (точні збіги)",[3836,13279,13280,13281,13284],{},"Потім всі ",[3769,13282,13283],{},".addMatcher()"," (умовні збіги)",[3836,13286,13287,13288,13291],{},"Нарешті ",[3769,13289,13290],{},".addDefaultCase()"," (якщо жодне правило не спрацювало)",[3743,13293,13294,13295,13297,13298,5572,13300,13303],{},"Якщо дія підпадає і під ",[3769,13296,9224],{},", і під ",[3769,13299,12494],{},[3829,13301,13302],{},"виконаються ОБА"," обробники!",[3762,13305,13307],{"className":3925,"code":13306,"language":3927,"meta":3767,"style":3767},"builder\n    .addCase(fetchTripsThunk.fulfilled, (state, action) => {\n        console.log('1. Конкретний обробник')\n        state.items = action.payload\n    })\n    .addMatcher(isFulfilled, (state) => {\n        console.log('2. Загальний matcher для всіх fulfilled')\n        state.loading = false\n    })\n\u002F\u002F При fetchTripsThunk.fulfilled виведеться:\n\u002F\u002F \"1. Конкретний обробник\"\n\u002F\u002F \"2. Загальний matcher для всіх fulfilled\"\n",[3769,13308,13309,13314,13343,13359,13375,13380,13400,13415,13427,13431,13436,13441],{"__ignoreMap":3767},[3772,13310,13311],{"class":3774,"line":3775},[3772,13312,13313],{"class":3949},"builder\n",[3772,13315,13316,13319,13321,13323,13325,13327,13329,13331,13333,13335,13337,13339,13341],{"class":3774,"line":3938},[3772,13317,13318],{"class":3945},"    .",[3772,13320,9224],{"class":3778},[3772,13322,5150],{"class":3945},[3772,13324,9229],{"class":3949},[3772,13326,4059],{"class":3945},[3772,13328,9279],{"class":3949},[3772,13330,7128],{"class":3945},[3772,13332,5153],{"class":3949},[3772,13334,3847],{"class":3945},[3772,13336,5163],{"class":3949},[3772,13338,5765],{"class":3945},[3772,13340,5768],{"class":3980},[3772,13342,4002],{"class":3945},[3772,13344,13345,13348,13350,13352,13354,13357],{"class":3774,"line":3961},[3772,13346,13347],{"class":3949},"        console",[3772,13349,4059],{"class":3945},[3772,13351,7289],{"class":3778},[3772,13353,5150],{"class":3945},[3772,13355,13356],{"class":3781},"'1. Конкретний обробник'",[3772,13358,5345],{"class":3945},[3772,13360,13361,13363,13365,13367,13369,13371,13373],{"class":3774,"line":3968},[3772,13362,9935],{"class":3949},[3772,13364,4059],{"class":3945},[3772,13366,5237],{"class":3949},[3772,13368,3988],{"class":3945},[3772,13370,5163],{"class":3949},[3772,13372,4059],{"class":3945},[3772,13374,6750],{"class":3949},[3772,13376,13377],{"class":3774,"line":3974},[3772,13378,13379],{"class":3945},"    })\n",[3772,13381,13382,13384,13386,13388,13390,13392,13394,13396,13398],{"class":3774,"line":3996},[3772,13383,13318],{"class":3945},[3772,13385,12494],{"class":3778},[3772,13387,5150],{"class":3945},[3772,13389,12510],{"class":3949},[3772,13391,7128],{"class":3945},[3772,13393,5153],{"class":3949},[3772,13395,5765],{"class":3945},[3772,13397,5768],{"class":3980},[3772,13399,4002],{"class":3945},[3772,13401,13402,13404,13406,13408,13410,13413],{"class":3774,"line":4005},[3772,13403,13347],{"class":3949},[3772,13405,4059],{"class":3945},[3772,13407,7289],{"class":3778},[3772,13409,5150],{"class":3945},[3772,13411,13412],{"class":3781},"'2. Загальний matcher для всіх fulfilled'",[3772,13414,5345],{"class":3945},[3772,13416,13417,13419,13421,13423,13425],{"class":3774,"line":4011},[3772,13418,9935],{"class":3949},[3772,13420,4059],{"class":3945},[3772,13422,6741],{"class":3949},[3772,13424,3988],{"class":3945},[3772,13426,9324],{"class":3980},[3772,13428,13429],{"class":3774,"line":4017},[3772,13430,13379],{"class":3945},[3772,13432,13433],{"class":3774,"line":4023},[3772,13434,13435],{"class":3934},"\u002F\u002F При fetchTripsThunk.fulfilled виведеться:\n",[3772,13437,13438],{"class":3774,"line":4028},[3772,13439,13440],{"class":3934},"\u002F\u002F \"1. Конкретний обробник\"\n",[3772,13442,13443],{"class":3774,"line":4034},[3772,13444,13445],{"class":3934},"\u002F\u002F \"2. Загальний matcher для всіх fulfilled\"\n",[9418,13447,13449],{"id":13448},"альтернативні-матчери-для-різних-сценаріїв","Альтернативні матчери для різних сценаріїв",[3743,13451,13452],{},"Redux Toolkit надає готові утиліти для роботи з групами дій:",[3762,13454,13456],{"className":3925,"code":13455,"language":3927,"meta":3767,"style":3767},"import {\n    isAnyOf, \u002F\u002F Хоча б одна умова істинна (OR)\n    isAllOf, \u002F\u002F Всі умови істинні (AND)\n    isPending, \u002F\u002F Дія має тип *.pending\n    isFulfilled, \u002F\u002F Дія має тип *.fulfilled\n    isRejected, \u002F\u002F Дія має тип *.rejected\n    isAsyncThunkAction, \u002F\u002F Будь-яка дія від createAsyncThunk\n} from '@reduxjs\u002Ftoolkit'\n\n\u002F\u002F Приклад: Універсальний індикатор завантаження для ВСІХ thunk-ів\nbuilder.addMatcher(\n    isAsyncThunkAction, \u002F\u002F Будь-яка асинхронна дія\n    (state, action) => {\n        if (isPending(action)) {\n            state.globalLoading = true\n        }\n        if (isFulfilled(action) || isRejected(action)) {\n            state.globalLoading = false\n        }\n    },\n)\n\n\u002F\u002F Приклад: Логування помилок тільки для конкретних thunk-ів\nbuilder.addMatcher(\n    isAllOf(isRejected, (action) => action.type.startsWith('trips\u002F')),\n    (state, action) => {\n        console.error('[TRIPS ERROR]', action.error)\n    },\n)\n",[3769,13457,13458,13464,13474,13484,13494,13504,13514,13524,13533,13537,13542,13552,13561,13578,13592,13605,13609,13632,13644,13648,13652,13656,13660,13665,13675,13710,13726,13749,13753],{"__ignoreMap":3767},[3772,13459,13460,13462],{"class":3774,"line":3775},[3772,13461,3942],{"class":3941},[3772,13463,4002],{"class":3945},[3772,13465,13466,13469,13471],{"class":3774,"line":3938},[3772,13467,13468],{"class":3949},"    isAnyOf",[3772,13470,3847],{"class":3945},[3772,13472,13473],{"class":3934},"\u002F\u002F Хоча б одна умова істинна (OR)\n",[3772,13475,13476,13479,13481],{"class":3774,"line":3961},[3772,13477,13478],{"class":3949},"    isAllOf",[3772,13480,3847],{"class":3945},[3772,13482,13483],{"class":3934},"\u002F\u002F Всі умови істинні (AND)\n",[3772,13485,13486,13489,13491],{"class":3774,"line":3968},[3772,13487,13488],{"class":3949},"    isPending",[3772,13490,3847],{"class":3945},[3772,13492,13493],{"class":3934},"\u002F\u002F Дія має тип *.pending\n",[3772,13495,13496,13499,13501],{"class":3774,"line":3974},[3772,13497,13498],{"class":3949},"    isFulfilled",[3772,13500,3847],{"class":3945},[3772,13502,13503],{"class":3934},"\u002F\u002F Дія має тип *.fulfilled\n",[3772,13505,13506,13509,13511],{"class":3774,"line":3996},[3772,13507,13508],{"class":3949},"    isRejected",[3772,13510,3847],{"class":3945},[3772,13512,13513],{"class":3934},"\u002F\u002F Дія має тип *.rejected\n",[3772,13515,13516,13519,13521],{"class":3774,"line":4005},[3772,13517,13518],{"class":3949},"    isAsyncThunkAction",[3772,13520,3847],{"class":3945},[3772,13522,13523],{"class":3934},"\u002F\u002F Будь-яка дія від createAsyncThunk\n",[3772,13525,13526,13529,13531],{"class":3774,"line":4011},[3772,13527,13528],{"class":3945},"} ",[3772,13530,3955],{"class":3941},[3772,13532,3958],{"class":3781},[3772,13534,13535],{"class":3774,"line":4017},[3772,13536,3965],{"emptyLinePlaceholder":3964},[3772,13538,13539],{"class":3774,"line":4023},[3772,13540,13541],{"class":3934},"\u002F\u002F Приклад: Універсальний індикатор завантаження для ВСІХ thunk-ів\n",[3772,13543,13544,13546,13548,13550],{"class":3774,"line":4028},[3772,13545,9197],{"class":3949},[3772,13547,4059],{"class":3945},[3772,13549,12494],{"class":3778},[3772,13551,12904],{"class":3945},[3772,13553,13554,13556,13558],{"class":3774,"line":4034},[3772,13555,13518],{"class":3949},[3772,13557,3847],{"class":3945},[3772,13559,13560],{"class":3934},"\u002F\u002F Будь-яка асинхронна дія\n",[3772,13562,13563,13566,13568,13570,13572,13574,13576],{"class":3774,"line":4068},[3772,13564,13565],{"class":3945},"    (",[3772,13567,5153],{"class":3949},[3772,13569,3847],{"class":3945},[3772,13571,5163],{"class":3949},[3772,13573,5765],{"class":3945},[3772,13575,5768],{"class":3980},[3772,13577,4002],{"class":3945},[3772,13579,13580,13582,13584,13586,13588,13590],{"class":3774,"line":4313},[3772,13581,10614],{"class":3941},[3772,13583,5179],{"class":3945},[3772,13585,12507],{"class":3778},[3772,13587,5150],{"class":3945},[3772,13589,5163],{"class":3949},[3772,13591,7386],{"class":3945},[3772,13593,13594,13596,13598,13601,13603],{"class":3774,"line":4470},[3772,13595,6598],{"class":3949},[3772,13597,4059],{"class":3945},[3772,13599,13600],{"class":3949},"globalLoading",[3772,13602,3988],{"class":3945},[3772,13604,4865],{"class":3980},[3772,13606,13607],{"class":3774,"line":4879},[3772,13608,5245],{"class":3945},[3772,13610,13611,13613,13615,13617,13619,13621,13624,13626,13628,13630],{"class":3774,"line":4892},[3772,13612,10614],{"class":3941},[3772,13614,5179],{"class":3945},[3772,13616,12510],{"class":3778},[3772,13618,5150],{"class":3945},[3772,13620,5163],{"class":3949},[3772,13622,13623],{"class":3945},") || ",[3772,13625,12513],{"class":3778},[3772,13627,5150],{"class":3945},[3772,13629,5163],{"class":3949},[3772,13631,7386],{"class":3945},[3772,13633,13634,13636,13638,13640,13642],{"class":3774,"line":4903},[3772,13635,6598],{"class":3949},[3772,13637,4059],{"class":3945},[3772,13639,13600],{"class":3949},[3772,13641,3988],{"class":3945},[3772,13643,9324],{"class":3980},[3772,13645,13646],{"class":3774,"line":4909},[3772,13647,5245],{"class":3945},[3772,13649,13650],{"class":3774,"line":5521},[3772,13651,4014],{"class":3945},[3772,13653,13654],{"class":3774,"line":5527},[3772,13655,5345],{"class":3945},[3772,13657,13658],{"class":3774,"line":5533},[3772,13659,3965],{"emptyLinePlaceholder":3964},[3772,13661,13662],{"class":3774,"line":5539},[3772,13663,13664],{"class":3934},"\u002F\u002F Приклад: Логування помилок тільки для конкретних thunk-ів\n",[3772,13666,13667,13669,13671,13673],{"class":3774,"line":5545},[3772,13668,9197],{"class":3949},[3772,13670,4059],{"class":3945},[3772,13672,12494],{"class":3778},[3772,13674,12904],{"class":3945},[3772,13676,13677,13679,13681,13683,13685,13687,13689,13691,13693,13695,13697,13699,13702,13704,13707],{"class":3774,"line":5550},[3772,13678,13478],{"class":3778},[3772,13680,5150],{"class":3945},[3772,13682,12513],{"class":3949},[3772,13684,7128],{"class":3945},[3772,13686,5163],{"class":3949},[3772,13688,5765],{"class":3945},[3772,13690,5768],{"class":3980},[3772,13692,7262],{"class":3949},[3772,13694,4059],{"class":3945},[3772,13696,5048],{"class":3949},[3772,13698,4059],{"class":3945},[3772,13700,13701],{"class":3778},"startsWith",[3772,13703,5150],{"class":3945},[3772,13705,13706],{"class":3781},"'trips\u002F'",[3772,13708,13709],{"class":3945},")),\n",[3772,13711,13712,13714,13716,13718,13720,13722,13724],{"class":3774,"line":6121},[3772,13713,13565],{"class":3945},[3772,13715,5153],{"class":3949},[3772,13717,3847],{"class":3945},[3772,13719,5163],{"class":3949},[3772,13721,5765],{"class":3945},[3772,13723,5768],{"class":3980},[3772,13725,4002],{"class":3945},[3772,13727,13728,13730,13732,13734,13736,13739,13741,13743,13745,13747],{"class":3774,"line":6131},[3772,13729,13347],{"class":3949},[3772,13731,4059],{"class":3945},[3772,13733,5072],{"class":3778},[3772,13735,5150],{"class":3945},[3772,13737,13738],{"class":3781},"'[TRIPS ERROR]'",[3772,13740,3847],{"class":3945},[3772,13742,5163],{"class":3949},[3772,13744,4059],{"class":3945},[3772,13746,5072],{"class":3949},[3772,13748,5345],{"class":3945},[3772,13750,13751],{"class":3774,"line":6136},[3772,13752,4014],{"class":3945},[3772,13754,13755],{"class":3774,"line":6142},[3772,13756,5345],{"class":3945},[10844,13758,13759,13812,13946],{},[10847,13760,13763,13770,13784,13790],{"icon":13761,"title":13762},"i-lucide-help-circle","Коли використовувати addCase vs addMatcher?",[3743,13764,13765],{},[3829,13766,9867,13767,13769],{},[3769,13768,9224],{},", коли:",[3833,13771,13772,13778],{},[3836,13773,13774,13775],{},"Потрібна унікальна логіка для ",[3829,13776,13777],{},"конкретної дії",[3836,13779,13780,13781],{},"Наприклад: оновлення конкретного поля після ",[3769,13782,13783],{},"fetchUserProfile.fulfilled",[3743,13785,13786],{},[3829,13787,9867,13788,13769],{},[3769,13789,12494],{},[3833,13791,13792,13799,13806],{},[3836,13793,13794,13795,13798],{},"Потрібна ",[3829,13796,13797],{},"спільна логіка"," для групи дій",[3836,13800,13801,13802,13805],{},"Наприклад: показ індикатора завантаження для всіх ",[3769,13803,13804],{},"*.pending"," дій",[3836,13807,13808,13809],{},"Або централізоване логування всіх помилок з ",[3769,13810,13811],{},"*.rejected",[10847,13813,13815,13821],{"icon":943,"title":13814},"Чи можна комбінувати addCase і addMatcher для однієї дії?",[3743,13816,6851,13817,13820],{},[3829,13818,13819],{},"Так!"," Це дозволяє мати загальну логіку (через matcher) та специфічну логіку (через case).",[3762,13822,13824],{"className":3925,"code":13823,"language":3927,"meta":3767,"style":3767},"builder\n    \u002F\u002F Специфічна логіка для конкретного fulfilled\n    .addCase(fetchTripsThunk.fulfilled, (state, action) => {\n        state.trips = action.payload\n    })\n    \u002F\u002F Загальна логіка для ВСІХ fulfilled (включно з fetchTripsThunk)\n    .addMatcher(isFulfilled, (state) => {\n        state.loading = false\n        state.lastUpdated = Date.now()\n    })\n",[3769,13825,13826,13830,13835,13863,13879,13883,13888,13908,13920,13942],{"__ignoreMap":3767},[3772,13827,13828],{"class":3774,"line":3775},[3772,13829,13313],{"class":3949},[3772,13831,13832],{"class":3774,"line":3938},[3772,13833,13834],{"class":3934},"    \u002F\u002F Специфічна логіка для конкретного fulfilled\n",[3772,13836,13837,13839,13841,13843,13845,13847,13849,13851,13853,13855,13857,13859,13861],{"class":3774,"line":3961},[3772,13838,13318],{"class":3945},[3772,13840,9224],{"class":3778},[3772,13842,5150],{"class":3945},[3772,13844,9229],{"class":3949},[3772,13846,4059],{"class":3945},[3772,13848,9279],{"class":3949},[3772,13850,7128],{"class":3945},[3772,13852,5153],{"class":3949},[3772,13854,3847],{"class":3945},[3772,13856,5163],{"class":3949},[3772,13858,5765],{"class":3945},[3772,13860,5768],{"class":3980},[3772,13862,4002],{"class":3945},[3772,13864,13865,13867,13869,13871,13873,13875,13877],{"class":3774,"line":3968},[3772,13866,9935],{"class":3949},[3772,13868,4059],{"class":3945},[3772,13870,7557],{"class":3949},[3772,13872,3988],{"class":3945},[3772,13874,5163],{"class":3949},[3772,13876,4059],{"class":3945},[3772,13878,6750],{"class":3949},[3772,13880,13881],{"class":3774,"line":3974},[3772,13882,13379],{"class":3945},[3772,13884,13885],{"class":3774,"line":3996},[3772,13886,13887],{"class":3934},"    \u002F\u002F Загальна логіка для ВСІХ fulfilled (включно з fetchTripsThunk)\n",[3772,13889,13890,13892,13894,13896,13898,13900,13902,13904,13906],{"class":3774,"line":4005},[3772,13891,13318],{"class":3945},[3772,13893,12494],{"class":3778},[3772,13895,5150],{"class":3945},[3772,13897,12510],{"class":3949},[3772,13899,7128],{"class":3945},[3772,13901,5153],{"class":3949},[3772,13903,5765],{"class":3945},[3772,13905,5768],{"class":3980},[3772,13907,4002],{"class":3945},[3772,13909,13910,13912,13914,13916,13918],{"class":3774,"line":4011},[3772,13911,9935],{"class":3949},[3772,13913,4059],{"class":3945},[3772,13915,6741],{"class":3949},[3772,13917,3988],{"class":3945},[3772,13919,9324],{"class":3980},[3772,13921,13922,13924,13926,13929,13931,13934,13936,13939],{"class":3774,"line":4017},[3772,13923,9935],{"class":3949},[3772,13925,4059],{"class":3945},[3772,13927,13928],{"class":3949},"lastUpdated",[3772,13930,3988],{"class":3945},[3772,13932,13933],{"class":3949},"Date",[3772,13935,4059],{"class":3945},[3772,13937,13938],{"class":3778},"now",[3772,13940,13941],{"class":3945},"()\n",[3772,13943,13944],{"class":3774,"line":4023},[3772,13945,13379],{"class":3945},[10847,13947,13950,13964,14038],{"icon":13948,"title":13949},"i-lucide-info","Що таке addDefaultCase і коли його використовувати?",[3743,13951,13952,13955,13956,13959,13960,9546,13962,4059],{},[3769,13953,13954],{},"addDefaultCase"," — це \"catch-all\" обробник, який спрацьовує, якщо ",[3829,13957,13958],{},"жодна"," дія не була оброблена через ",[3769,13961,9224],{},[3769,13963,12494],{},[3762,13965,13967],{"className":3925,"code":13966,"language":3927,"meta":3767,"style":3767},"builder.addDefaultCase((state, action) => {\n    \u002F\u002F Логування всіх необроблених дій (корисно для дебагу)\n    if (__DEV__) {\n        console.log('Unhandled action:', action.type)\n    }\n})\n",[3769,13968,13969,13991,13996,14007,14030,14034],{"__ignoreMap":3767},[3772,13970,13971,13973,13975,13977,13979,13981,13983,13985,13987,13989],{"class":3774,"line":3775},[3772,13972,9197],{"class":3949},[3772,13974,4059],{"class":3945},[3772,13976,13954],{"class":3778},[3772,13978,6056],{"class":3945},[3772,13980,5153],{"class":3949},[3772,13982,3847],{"class":3945},[3772,13984,5163],{"class":3949},[3772,13986,5765],{"class":3945},[3772,13988,5768],{"class":3980},[3772,13990,4002],{"class":3945},[3772,13992,13993],{"class":3774,"line":3938},[3772,13994,13995],{"class":3934},"    \u002F\u002F Логування всіх необроблених дій (корисно для дебагу)\n",[3772,13997,13998,14000,14002,14005],{"class":3774,"line":3961},[3772,13999,5176],{"class":3941},[3772,14001,5179],{"class":3945},[3772,14003,14004],{"class":3949},"__DEV__",[3772,14006,5166],{"class":3945},[3772,14008,14009,14011,14013,14015,14017,14020,14022,14024,14026,14028],{"class":3774,"line":3968},[3772,14010,13347],{"class":3949},[3772,14012,4059],{"class":3945},[3772,14014,7289],{"class":3778},[3772,14016,5150],{"class":3945},[3772,14018,14019],{"class":3781},"'Unhandled action:'",[3772,14021,3847],{"class":3945},[3772,14023,5163],{"class":3949},[3772,14025,4059],{"class":3945},[3772,14027,5048],{"class":3949},[3772,14029,5345],{"class":3945},[3772,14031,14032],{"class":3774,"line":3974},[3772,14033,4906],{"class":3945},[3772,14035,14036],{"class":3774,"line":3996},[3772,14037,4020],{"class":3945},[3743,14039,14040,14041,14044],{},"⚠️ ",[3829,14042,14043],{},"Використовуйте обережно:"," Це може призвести до непотрібних перерендерів, якщо ви змінюєте стан для кожної дії!",[9418,14046,14048],{"id":14047},"практичний-приклад-міжслайсова-синхронізація","Практичний приклад: Міжслайсова синхронізація",[3743,14050,14051,14052,14054],{},"Уявімо, що при виході користувача (",[3769,14053,11897],{},") потрібно очистити дані у всіх slice-ах:",[3762,14056,14058],{"className":3925,"code":14057,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FuserSlice.ts\nexport const userSlice = createSlice({\n    name: 'user',\n    initialState,\n    reducers: {\n        logout(state) {\n            state.profile = null\n            state.isAuthenticated = false\n        },\n    },\n})\n\nexport const { logout } = userSlice.actions\n\n\u002F\u002F src\u002Fstore\u002Fslices\u002FtripsSlice.ts\nimport { logout } from '.\u002FuserSlice'\n\nexport const tripsSlice = createSlice({\n    name: 'trips',\n    initialState,\n    reducers: {},\n    extraReducers: (builder) => {\n        builder.addCase(logout, (state) => {\n            \u002F\u002F Реагуємо на logout з userSlice\n            state.items = []\n            state.error = null\n        })\n    },\n})\n\n\u002F\u002F src\u002Fstore\u002Fslices\u002FfavoritesSlice.ts\nimport { logout } from '.\u002FuserSlice'\n\nexport const favoritesSlice = createSlice({\n    name: 'favorites',\n    initialState,\n    reducers: {},\n    extraReducers: (builder) => {\n        builder.addCase(logout, (state) => {\n            \u002F\u002F Також очищаємо улюблені поїздки\n            state.favoriteIds = []\n        })\n    },\n})\n",[3769,14059,14060,14065,14080,14089,14095,14101,14112,14125,14138,14142,14146,14150,14154,14172,14176,14180,14195,14199,14213,14221,14227,14233,14249,14272,14277,14287,14299,14304,14308,14312,14316,14321,14335,14339,14354,14363,14369,14375,14391,14413,14418,14429,14433,14437],{"__ignoreMap":3767},[3772,14061,14062],{"class":3774,"line":3775},[3772,14063,14064],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fslices\u002FuserSlice.ts\n",[3772,14066,14067,14069,14071,14074,14076,14078],{"class":3774,"line":3938},[3772,14068,3977],{"class":3941},[3772,14070,3981],{"class":3980},[3772,14072,14073],{"class":3984}," userSlice",[3772,14075,3988],{"class":3945},[3772,14077,3846],{"class":3778},[3772,14079,3993],{"class":3945},[3772,14081,14082,14084,14087],{"class":3774,"line":3961},[3772,14083,6540],{"class":3949},[3772,14085,14086],{"class":3781}," 'user'",[3772,14088,4806],{"class":3945},[3772,14090,14091,14093],{"class":3774,"line":3968},[3772,14092,6550],{"class":3949},[3772,14094,4806],{"class":3945},[3772,14096,14097,14099],{"class":3774,"line":3974},[3772,14098,6557],{"class":3949},[3772,14100,4002],{"class":3945},[3772,14102,14103,14106,14108,14110],{"class":3774,"line":3996},[3772,14104,14105],{"class":3778},"        logout",[3772,14107,5150],{"class":3945},[3772,14109,5153],{"class":3949},[3772,14111,5166],{"class":3945},[3772,14113,14114,14116,14118,14121,14123],{"class":3774,"line":4005},[3772,14115,6598],{"class":3949},[3772,14117,4059],{"class":3945},[3772,14119,14120],{"class":3949},"profile",[3772,14122,3988],{"class":3945},[3772,14124,4816],{"class":3980},[3772,14126,14127,14129,14131,14134,14136],{"class":3774,"line":4011},[3772,14128,6598],{"class":3949},[3772,14130,4059],{"class":3945},[3772,14132,14133],{"class":3949},"isAuthenticated",[3772,14135,3988],{"class":3945},[3772,14137,9324],{"class":3980},[3772,14139,14140],{"class":3774,"line":4017},[3772,14141,6621],{"class":3945},[3772,14143,14144],{"class":3774,"line":4023},[3772,14145,4014],{"class":3945},[3772,14147,14148],{"class":3774,"line":4028},[3772,14149,4020],{"class":3945},[3772,14151,14152],{"class":3774,"line":4034},[3772,14153,3965],{"emptyLinePlaceholder":3964},[3772,14155,14156,14158,14160,14162,14164,14166,14168,14170],{"class":3774,"line":4068},[3772,14157,3977],{"class":3941},[3772,14159,3981],{"class":3980},[3772,14161,3946],{"class":3945},[3772,14163,11897],{"class":3984},[3772,14165,6801],{"class":3945},[3772,14167,8419],{"class":3949},[3772,14169,4059],{"class":3945},[3772,14171,6809],{"class":3949},[3772,14173,14174],{"class":3774,"line":4313},[3772,14175,3965],{"emptyLinePlaceholder":3964},[3772,14177,14178],{"class":3774,"line":4470},[3772,14179,6348],{"class":3934},[3772,14181,14182,14184,14186,14188,14190,14192],{"class":3774,"line":4879},[3772,14183,3942],{"class":3941},[3772,14185,3946],{"class":3945},[3772,14187,11897],{"class":3949},[3772,14189,3952],{"class":3945},[3772,14191,3955],{"class":3941},[3772,14193,14194],{"class":3781}," '.\u002FuserSlice'\n",[3772,14196,14197],{"class":3774,"line":4892},[3772,14198,3965],{"emptyLinePlaceholder":3964},[3772,14200,14201,14203,14205,14207,14209,14211],{"class":3774,"line":4903},[3772,14202,3977],{"class":3941},[3772,14204,3981],{"class":3980},[3772,14206,6529],{"class":3984},[3772,14208,3988],{"class":3945},[3772,14210,3846],{"class":3778},[3772,14212,3993],{"class":3945},[3772,14214,14215,14217,14219],{"class":3774,"line":4909},[3772,14216,6540],{"class":3949},[3772,14218,6543],{"class":3781},[3772,14220,4806],{"class":3945},[3772,14222,14223,14225],{"class":3774,"line":5521},[3772,14224,6550],{"class":3949},[3772,14226,4806],{"class":3945},[3772,14228,14229,14231],{"class":3774,"line":5527},[3772,14230,6557],{"class":3949},[3772,14232,12632],{"class":3945},[3772,14234,14235,14237,14239,14241,14243,14245,14247],{"class":3774,"line":5533},[3772,14236,9190],{"class":3778},[3772,14238,4094],{"class":3949},[3772,14240,5179],{"class":3945},[3772,14242,9197],{"class":3949},[3772,14244,5765],{"class":3945},[3772,14246,5768],{"class":3980},[3772,14248,4002],{"class":3945},[3772,14250,14251,14254,14256,14258,14260,14262,14264,14266,14268,14270],{"class":3774,"line":5539},[3772,14252,14253],{"class":3949},"        builder",[3772,14255,4059],{"class":3945},[3772,14257,9224],{"class":3778},[3772,14259,5150],{"class":3945},[3772,14261,11897],{"class":3949},[3772,14263,7128],{"class":3945},[3772,14265,5153],{"class":3949},[3772,14267,5765],{"class":3945},[3772,14269,5768],{"class":3980},[3772,14271,4002],{"class":3945},[3772,14273,14274],{"class":3774,"line":5545},[3772,14275,14276],{"class":3934},"            \u002F\u002F Реагуємо на logout з userSlice\n",[3772,14278,14279,14281,14283,14285],{"class":3774,"line":5550},[3772,14280,6598],{"class":3949},[3772,14282,4059],{"class":3945},[3772,14284,5237],{"class":3949},[3772,14286,8709],{"class":3945},[3772,14288,14289,14291,14293,14295,14297],{"class":3774,"line":6121},[3772,14290,6598],{"class":3949},[3772,14292,4059],{"class":3945},[3772,14294,5072],{"class":3949},[3772,14296,3988],{"class":3945},[3772,14298,4816],{"class":3980},[3772,14300,14301],{"class":3774,"line":6131},[3772,14302,14303],{"class":3945},"        })\n",[3772,14305,14306],{"class":3774,"line":6136},[3772,14307,4014],{"class":3945},[3772,14309,14310],{"class":3774,"line":6142},[3772,14311,4020],{"class":3945},[3772,14313,14314],{"class":3774,"line":6150},[3772,14315,3965],{"emptyLinePlaceholder":3964},[3772,14317,14318],{"class":3774,"line":6157},[3772,14319,14320],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fslices\u002FfavoritesSlice.ts\n",[3772,14322,14323,14325,14327,14329,14331,14333],{"class":3774,"line":6162},[3772,14324,3942],{"class":3941},[3772,14326,3946],{"class":3945},[3772,14328,11897],{"class":3949},[3772,14330,3952],{"class":3945},[3772,14332,3955],{"class":3941},[3772,14334,14194],{"class":3781},[3772,14336,14337],{"class":3774,"line":6629},[3772,14338,3965],{"emptyLinePlaceholder":3964},[3772,14340,14341,14343,14345,14348,14350,14352],{"class":3774,"line":6653},[3772,14342,3977],{"class":3941},[3772,14344,3981],{"class":3980},[3772,14346,14347],{"class":3984}," favoritesSlice",[3772,14349,3988],{"class":3945},[3772,14351,3846],{"class":3778},[3772,14353,3993],{"class":3945},[3772,14355,14356,14358,14361],{"class":3774,"line":6698},[3772,14357,6540],{"class":3949},[3772,14359,14360],{"class":3781}," 'favorites'",[3772,14362,4806],{"class":3945},[3772,14364,14365,14367],{"class":3774,"line":6703},[3772,14366,6550],{"class":3949},[3772,14368,4806],{"class":3945},[3772,14370,14371,14373],{"class":3774,"line":6709},[3772,14372,6557],{"class":3949},[3772,14374,12632],{"class":3945},[3772,14376,14377,14379,14381,14383,14385,14387,14389],{"class":3774,"line":6734},[3772,14378,9190],{"class":3778},[3772,14380,4094],{"class":3949},[3772,14382,5179],{"class":3945},[3772,14384,9197],{"class":3949},[3772,14386,5765],{"class":3945},[3772,14388,5768],{"class":3980},[3772,14390,4002],{"class":3945},[3772,14392,14393,14395,14397,14399,14401,14403,14405,14407,14409,14411],{"class":3774,"line":6753},[3772,14394,14253],{"class":3949},[3772,14396,4059],{"class":3945},[3772,14398,9224],{"class":3778},[3772,14400,5150],{"class":3945},[3772,14402,11897],{"class":3949},[3772,14404,7128],{"class":3945},[3772,14406,5153],{"class":3949},[3772,14408,5765],{"class":3945},[3772,14410,5768],{"class":3980},[3772,14412,4002],{"class":3945},[3772,14414,14415],{"class":3774,"line":6758},[3772,14416,14417],{"class":3934},"            \u002F\u002F Також очищаємо улюблені поїздки\n",[3772,14419,14420,14422,14424,14427],{"class":3774,"line":6763},[3772,14421,6598],{"class":3949},[3772,14423,4059],{"class":3945},[3772,14425,14426],{"class":3949},"favoriteIds",[3772,14428,8709],{"class":3945},[3772,14430,14431],{"class":3774,"line":6768},[3772,14432,14303],{"class":3945},[3772,14434,14435],{"class":3774,"line":6773},[3772,14436,4014],{"class":3945},[3772,14438,14439],{"class":3774,"line":6779},[3772,14440,4020],{"class":3945},[3743,14442,14443,14444,14447],{},"Тепер один ",[3769,14445,14446],{},"dispatch(logout())"," автоматично синхронізує три slice-и!",[4495,14449],{},[4495,14451],{},[3747,14453,14455,14456,14458],{"id":14454},"_4-store-configurestore-та-конвеєр-middleware","4. Store (",[3769,14457,3850],{},") та конвеєр Middleware",[3743,14460,14461,14463,14464,14466,14467,7467],{},[3829,14462,4694],{}," створюється функцією ",[3769,14465,3850],{},", яка об'єднує всі слайси в єдине дерево та автоматично налаштовує стандартний конвеєр проміжного ПЗ (",[4508,14468,14469],{},"Middleware Pipeline",[4495,14471],{},[3738,14473,14475],{"id":14474},"практичний-приклад-повний-цикл-від-дії-до-ui","Практичний приклад: Повний цикл від дії до UI",[3743,14477,14478,14479,4059],{},"Щоб зрозуміти, як усе працює разом, розглянемо реальний сценарій: ",[3829,14480,14481],{},"користувач натискає кнопку \"Лайк\" на картці поїздки",[3747,14483,14485],{"id":14484},"крок-1-користувач-натискає-кнопку","Крок 1: Користувач натискає кнопку",[3762,14487,14489],{"className":4129,"code":14488,"language":4131,"meta":3767,"style":3767},"\u002F\u002F src\u002Fcomponents\u002FTripCard.tsx\nimport React from 'react'\nimport { Pressable, Text } from 'react-native'\nimport { useAppDispatch, useAppSelector } from '@\u002Fstore\u002Fhooks'\nimport { toggleLikeThunk } from '@\u002Fstore\u002Fthunks\u002FlikesThunks'\n\nexport function TripCard({ tripId }: { tripId: string }) {\n    const dispatch = useAppDispatch()\n\n    \u002F\u002F Отримуємо стан лайка зі store\n    const isLiked = useAppSelector((state) => state.likes.byTripId[tripId] ?? false)\n    const isLoading = useAppSelector((state) => state.likes.loading)\n\n    const handleLike = () => {\n        \u002F\u002F 1️⃣ Користувач натискає — відправляємо дію\n        dispatch(toggleLikeThunk({ tripId }))\n    }\n\n    return (\n        \u003CPressable onPress={handleLike} disabled={isLoading}>\n            \u003CText>{isLiked ? '❤️' : '🤍'}\u003C\u002FText>\n        \u003C\u002FPressable>\n    )\n}\n",[3769,14490,14491,14496,14508,14529,14549,14565,14569,14594,14607,14611,14616,14657,14688,14692,14706,14711,14726,14730,14734,14740,14772,14807,14815,14819],{"__ignoreMap":3767},[3772,14492,14493],{"class":3774,"line":3775},[3772,14494,14495],{"class":3934},"\u002F\u002F src\u002Fcomponents\u002FTripCard.tsx\n",[3772,14497,14498,14500,14503,14505],{"class":3774,"line":3938},[3772,14499,3942],{"class":3941},[3772,14501,14502],{"class":3949}," React",[3772,14504,6211],{"class":3941},[3772,14506,14507],{"class":3781}," 'react'\n",[3772,14509,14510,14512,14514,14517,14519,14522,14524,14526],{"class":3774,"line":3961},[3772,14511,3942],{"class":3941},[3772,14513,3946],{"class":3945},[3772,14515,14516],{"class":3949},"Pressable",[3772,14518,3847],{"class":3945},[3772,14520,14521],{"class":3949},"Text",[3772,14523,3952],{"class":3945},[3772,14525,3955],{"class":3941},[3772,14527,14528],{"class":3781}," 'react-native'\n",[3772,14530,14531,14533,14535,14538,14540,14542,14544,14546],{"class":3774,"line":3968},[3772,14532,3942],{"class":3941},[3772,14534,3946],{"class":3945},[3772,14536,14537],{"class":3949},"useAppDispatch",[3772,14539,3847],{"class":3945},[3772,14541,10952],{"class":3949},[3772,14543,3952],{"class":3945},[3772,14545,3955],{"class":3941},[3772,14547,14548],{"class":3781}," '@\u002Fstore\u002Fhooks'\n",[3772,14550,14551,14553,14555,14558,14560,14562],{"class":3774,"line":3974},[3772,14552,3942],{"class":3941},[3772,14554,3946],{"class":3945},[3772,14556,14557],{"class":3949},"toggleLikeThunk",[3772,14559,3952],{"class":3945},[3772,14561,3955],{"class":3941},[3772,14563,14564],{"class":3781}," '@\u002Fstore\u002Fthunks\u002FlikesThunks'\n",[3772,14566,14567],{"class":3774,"line":3996},[3772,14568,3965],{"emptyLinePlaceholder":3964},[3772,14570,14571,14573,14575,14578,14580,14582,14585,14587,14589,14591],{"class":3774,"line":4005},[3772,14572,3977],{"class":3941},[3772,14574,4199],{"class":3980},[3772,14576,14577],{"class":3778}," TripCard",[3772,14579,10074],{"class":3945},[3772,14581,7598],{"class":3949},[3772,14583,14584],{"class":3945}," }: { ",[3772,14586,7598],{"class":3949},[3772,14588,4800],{"class":3945},[3772,14590,6459],{"class":4042},[3772,14592,14593],{"class":3945}," }) {\n",[3772,14595,14596,14598,14601,14603,14605],{"class":3774,"line":4011},[3772,14597,10944],{"class":3980},[3772,14599,14600],{"class":3984}," dispatch",[3772,14602,3988],{"class":3945},[3772,14604,14537],{"class":3778},[3772,14606,13941],{"class":3945},[3772,14608,14609],{"class":3774,"line":4017},[3772,14610,3965],{"emptyLinePlaceholder":3964},[3772,14612,14613],{"class":3774,"line":4023},[3772,14614,14615],{"class":3934},"    \u002F\u002F Отримуємо стан лайка зі store\n",[3772,14617,14618,14620,14623,14625,14627,14629,14631,14633,14635,14637,14639,14641,14643,14646,14648,14650,14653,14655],{"class":3774,"line":4028},[3772,14619,10944],{"class":3980},[3772,14621,14622],{"class":3984}," isLiked",[3772,14624,3988],{"class":3945},[3772,14626,10952],{"class":3778},[3772,14628,6056],{"class":3945},[3772,14630,5153],{"class":3949},[3772,14632,5765],{"class":3945},[3772,14634,5768],{"class":3980},[3772,14636,5353],{"class":3949},[3772,14638,4059],{"class":3945},[3772,14640,8983],{"class":3949},[3772,14642,4059],{"class":3945},[3772,14644,14645],{"class":3949},"byTripId",[3772,14647,10793],{"class":3945},[3772,14649,7598],{"class":3949},[3772,14651,14652],{"class":3945},"] ?? ",[3772,14654,4803],{"class":3980},[3772,14656,5345],{"class":3945},[3772,14658,14659,14661,14664,14666,14668,14670,14672,14674,14676,14678,14680,14682,14684,14686],{"class":3774,"line":4034},[3772,14660,10944],{"class":3980},[3772,14662,14663],{"class":3984}," isLoading",[3772,14665,3988],{"class":3945},[3772,14667,10952],{"class":3778},[3772,14669,6056],{"class":3945},[3772,14671,5153],{"class":3949},[3772,14673,5765],{"class":3945},[3772,14675,5768],{"class":3980},[3772,14677,5353],{"class":3949},[3772,14679,4059],{"class":3945},[3772,14681,8983],{"class":3949},[3772,14683,4059],{"class":3945},[3772,14685,6741],{"class":3949},[3772,14687,5345],{"class":3945},[3772,14689,14690],{"class":3774,"line":4068},[3772,14691,3965],{"emptyLinePlaceholder":3964},[3772,14693,14694,14696,14699,14702,14704],{"class":3774,"line":4313},[3772,14695,10944],{"class":3980},[3772,14697,14698],{"class":3778}," handleLike",[3772,14700,14701],{"class":3945}," = () ",[3772,14703,5768],{"class":3980},[3772,14705,4002],{"class":3945},[3772,14707,14708],{"class":3774,"line":4470},[3772,14709,14710],{"class":3934},"        \u002F\u002F 1️⃣ Користувач натискає — відправляємо дію\n",[3772,14712,14713,14716,14718,14720,14722,14724],{"class":3774,"line":4879},[3772,14714,14715],{"class":3778},"        dispatch",[3772,14717,5150],{"class":3945},[3772,14719,14557],{"class":3778},[3772,14721,10074],{"class":3945},[3772,14723,7598],{"class":3949},[3772,14725,10088],{"class":3945},[3772,14727,14728],{"class":3774,"line":4892},[3772,14729,4906],{"class":3945},[3772,14731,14732],{"class":3774,"line":4903},[3772,14733,3965],{"emptyLinePlaceholder":3964},[3772,14735,14736,14738],{"class":3774,"line":4909},[3772,14737,4210],{"class":3941},[3772,14739,4213],{"class":3945},[3772,14741,14742,14744,14746,14749,14751,14753,14756,14758,14761,14763,14765,14768,14770],{"class":3774,"line":5521},[3772,14743,4219],{"class":4218},[3772,14745,14516],{"class":4042},[3772,14747,14748],{"class":4224}," onPress",[3772,14750,4227],{"class":3945},[3772,14752,4230],{"class":3980},[3772,14754,14755],{"class":3949},"handleLike",[3772,14757,4235],{"class":3980},[3772,14759,14760],{"class":4224}," disabled",[3772,14762,4227],{"class":3945},[3772,14764,4230],{"class":3980},[3772,14766,14767],{"class":3949},"isLoading",[3772,14769,4235],{"class":3980},[3772,14771,4065],{"class":4218},[3772,14773,14774,14776,14778,14781,14783,14786,14789,14792,14795,14798,14800,14803,14805],{"class":3774,"line":5527},[3772,14775,4242],{"class":4218},[3772,14777,14521],{"class":4042},[3772,14779,14780],{"class":4218},">",[3772,14782,4230],{"class":3980},[3772,14784,14785],{"class":3949},"isLiked",[3772,14787,14788],{"class":3945}," ?",[3772,14790,14791],{"class":3781}," '❤️'",[3772,14793,14794],{"class":3945}," :",[3772,14796,14797],{"class":3781}," '🤍'",[3772,14799,4235],{"class":3980},[3772,14801,14802],{"class":4218},"\u003C\u002F",[3772,14804,14521],{"class":4042},[3772,14806,4065],{"class":4218},[3772,14808,14809,14811,14813],{"class":3774,"line":5533},[3772,14810,4301],{"class":4218},[3772,14812,14516],{"class":4042},[3772,14814,4065],{"class":4218},[3772,14816,14817],{"class":3774,"line":5539},[3772,14818,4310],{"class":3945},[3772,14820,14821],{"class":3774,"line":5545},[3772,14822,4316],{"class":3945},[3747,14824,14826],{"id":14825},"крок-2-dispatch-відправляє-дію-в-store","Крок 2: Dispatch відправляє дію в Store",[3762,14828,14830],{"className":3925,"code":14829,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Коли ви викликаєте dispatch(toggleLikeThunk({ tripId: '123' }))\n\u002F\u002F відбувається наступне:\n\n\u002F\u002F 1. Redux відправляє PENDING дію:\n{\n    type: 'likes\u002FtoggleLike\u002Fpending',\n    meta: {\n        requestId: 'xR3k...',\n        arg: { tripId: '123' }\n    }\n}\n",[3769,14831,14832,14837,14842,14846,14851,14855,14866,14872,14884,14900,14904],{"__ignoreMap":3767},[3772,14833,14834],{"class":3774,"line":3775},[3772,14835,14836],{"class":3934},"\u002F\u002F Коли ви викликаєте dispatch(toggleLikeThunk({ tripId: '123' }))\n",[3772,14838,14839],{"class":3774,"line":3938},[3772,14840,14841],{"class":3934},"\u002F\u002F відбувається наступне:\n",[3772,14843,14844],{"class":3774,"line":3961},[3772,14845,3965],{"emptyLinePlaceholder":3964},[3772,14847,14848],{"class":3774,"line":3968},[3772,14849,14850],{"class":3934},"\u002F\u002F 1. Redux відправляє PENDING дію:\n",[3772,14852,14853],{"class":3774,"line":3974},[3772,14854,4714],{"class":3945},[3772,14856,14857,14859,14861,14864],{"class":3774,"line":3996},[3772,14858,4970],{"class":4719},[3772,14860,4800],{"class":3945},[3772,14862,14863],{"class":3781},"'likes\u002FtoggleLike\u002Fpending'",[3772,14865,4806],{"class":3945},[3772,14867,14868,14870],{"class":3774,"line":4005},[3772,14869,7006],{"class":4719},[3772,14871,4723],{"class":3945},[3772,14873,14874,14877,14879,14882],{"class":3774,"line":4011},[3772,14875,14876],{"class":4719},"        requestId",[3772,14878,4800],{"class":3945},[3772,14880,14881],{"class":3781},"'xR3k...'",[3772,14883,4806],{"class":3945},[3772,14885,14886,14889,14891,14893,14895,14898],{"class":3774,"line":4017},[3772,14887,14888],{"class":4719},"        arg",[3772,14890,4835],{"class":3945},[3772,14892,7598],{"class":4719},[3772,14894,4800],{"class":3945},[3772,14896,14897],{"class":3781},"'123'",[3772,14899,4787],{"class":3945},[3772,14901,14902],{"class":3774,"line":4023},[3772,14903,4906],{"class":3945},[3772,14905,14906],{"class":3774,"line":4028},[3772,14907,4316],{"class":3945},[3747,14909,14911],{"id":14910},"крок-3-thunk-виконує-асинхронну-логіку","Крок 3: Thunk виконує асинхронну логіку",[3762,14913,14915],{"className":3925,"code":14914,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fthunks\u002FlikesThunks.ts\nimport { createAsyncThunk } from '@reduxjs\u002Ftoolkit'\nimport { apiClient } from '@\u002Fapi\u002Fclient'\nimport type { RootState } from '..\u002Findex'\n\nexport const toggleLikeThunk = createAsyncThunk\u003C\n    { tripId: string; isLiked: boolean }, \u002F\u002F Успішний результат\n    { tripId: string }, \u002F\u002F Вхідний аргумент\n    {\n        state: RootState\n        rejectValue: { tripId: string; previousState: boolean }\n    }\n>('likes\u002FtoggleLike', async ({ tripId }, { getState, rejectWithValue }) => {\n    \u002F\u002F 2️⃣ Зберігаємо поточний стан для можливого rollback\n    const previousState = getState().likes.byTripId[tripId] ?? false\n\n    try {\n        \u002F\u002F 3️⃣ Відправляємо запит на сервер\n        const response = await apiClient.post(`\u002Ftrips\u002F${tripId}\u002Flike`, {\n            liked: !previousState,\n        })\n\n        \u002F\u002F 4️⃣ Успіх — повертаємо нові дані\n        return {\n            tripId,\n            isLiked: response.data.liked,\n        }\n    } catch (error) {\n        \u002F\u002F 5️⃣ Помилка — повертаємо дані для rollback\n        return rejectWithValue({\n            tripId,\n            previousState,\n        })\n    }\n})\n",[3769,14916,14917,14922,14936,14952,14970,14974,14990,15015,15030,15035,15044,15068,15072,15107,15112,15139,15143,15150,15155,15193,15204,15208,15212,15217,15223,15230,15248,15252,15266,15271,15280,15286,15293,15297,15301],{"__ignoreMap":3767},[3772,14918,14919],{"class":3774,"line":3775},[3772,14920,14921],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fthunks\u002FlikesThunks.ts\n",[3772,14923,14924,14926,14928,14930,14932,14934],{"class":3774,"line":3938},[3772,14925,3942],{"class":3941},[3772,14927,3946],{"class":3945},[3772,14929,3853],{"class":3949},[3772,14931,3952],{"class":3945},[3772,14933,3955],{"class":3941},[3772,14935,3958],{"class":3781},[3772,14937,14938,14940,14942,14945,14947,14949],{"class":3774,"line":3961},[3772,14939,3942],{"class":3941},[3772,14941,3946],{"class":3945},[3772,14943,14944],{"class":3949},"apiClient",[3772,14946,3952],{"class":3945},[3772,14948,3955],{"class":3941},[3772,14950,14951],{"class":3781}," '@\u002Fapi\u002Fclient'\n",[3772,14953,14954,14956,14958,14960,14963,14965,14967],{"class":3774,"line":3968},[3772,14955,3942],{"class":3941},[3772,14957,4039],{"class":3941},[3772,14959,3946],{"class":3945},[3772,14961,14962],{"class":3949},"RootState",[3772,14964,3952],{"class":3945},[3772,14966,3955],{"class":3941},[3772,14968,14969],{"class":3781}," '..\u002Findex'\n",[3772,14971,14972],{"class":3774,"line":3974},[3772,14973,3965],{"emptyLinePlaceholder":3964},[3772,14975,14976,14978,14980,14983,14985,14987],{"class":3774,"line":3996},[3772,14977,3977],{"class":3941},[3772,14979,3981],{"class":3980},[3772,14981,14982],{"class":3984}," toggleLikeThunk",[3772,14984,3988],{"class":3945},[3772,14986,3853],{"class":3949},[3772,14988,14989],{"class":3945},"\u003C\n",[3772,14991,14992,14995,14997,14999,15001,15003,15005,15007,15009,15012],{"class":3774,"line":4005},[3772,14993,14994],{"class":3945},"    { ",[3772,14996,7598],{"class":4719},[3772,14998,4800],{"class":3945},[3772,15000,6459],{"class":3949},[3772,15002,7818],{"class":3945},[3772,15004,14785],{"class":4719},[3772,15006,4800],{"class":3945},[3772,15008,6729],{"class":3949},[3772,15010,15011],{"class":3945}," }, ",[3772,15013,15014],{"class":3934},"\u002F\u002F Успішний результат\n",[3772,15016,15017,15019,15021,15023,15025,15027],{"class":3774,"line":4011},[3772,15018,14994],{"class":3945},[3772,15020,7598],{"class":4719},[3772,15022,4800],{"class":3945},[3772,15024,6459],{"class":3949},[3772,15026,15011],{"class":3945},[3772,15028,15029],{"class":3934},"\u002F\u002F Вхідний аргумент\n",[3772,15031,15032],{"class":3774,"line":4017},[3772,15033,15034],{"class":3945},"    {\n",[3772,15036,15037,15039,15041],{"class":3774,"line":4023},[3772,15038,9935],{"class":4719},[3772,15040,4800],{"class":3945},[3772,15042,15043],{"class":3949},"RootState\n",[3772,15045,15046,15049,15051,15053,15055,15057,15059,15062,15064,15066],{"class":3774,"line":4028},[3772,15047,15048],{"class":4719},"        rejectValue",[3772,15050,4835],{"class":3945},[3772,15052,7598],{"class":4719},[3772,15054,4800],{"class":3945},[3772,15056,6459],{"class":3949},[3772,15058,7818],{"class":3945},[3772,15060,15061],{"class":4719},"previousState",[3772,15063,4800],{"class":3945},[3772,15065,6729],{"class":3949},[3772,15067,4787],{"class":3945},[3772,15069,15070],{"class":3774,"line":4034},[3772,15071,4906],{"class":3945},[3772,15073,15074,15077,15080,15082,15085,15088,15090,15093,15095,15097,15100,15103,15105],{"class":3774,"line":4068},[3772,15075,15076],{"class":3945},">(",[3772,15078,15079],{"class":3781},"'likes\u002FtoggleLike'",[3772,15081,3847],{"class":3945},[3772,15083,15084],{"class":3980},"async",[3772,15086,15087],{"class":3945}," ({ ",[3772,15089,7598],{"class":3949},[3772,15091,15092],{"class":3945}," }, { ",[3772,15094,4062],{"class":3949},[3772,15096,3847],{"class":3945},[3772,15098,15099],{"class":3949},"rejectWithValue",[3772,15101,15102],{"class":3945}," }) ",[3772,15104,5768],{"class":3980},[3772,15106,4002],{"class":3945},[3772,15108,15109],{"class":3774,"line":4313},[3772,15110,15111],{"class":3934},"    \u002F\u002F 2️⃣ Зберігаємо поточний стан для можливого rollback\n",[3772,15113,15114,15116,15119,15121,15123,15125,15127,15129,15131,15133,15135,15137],{"class":3774,"line":4470},[3772,15115,10944],{"class":3980},[3772,15117,15118],{"class":3984}," previousState",[3772,15120,3988],{"class":3945},[3772,15122,4062],{"class":3778},[3772,15124,7205],{"class":3945},[3772,15126,8983],{"class":3949},[3772,15128,4059],{"class":3945},[3772,15130,14645],{"class":3949},[3772,15132,10793],{"class":3945},[3772,15134,7598],{"class":3949},[3772,15136,14652],{"class":3945},[3772,15138,9324],{"class":3980},[3772,15140,15141],{"class":3774,"line":4879},[3772,15142,3965],{"emptyLinePlaceholder":3964},[3772,15144,15145,15148],{"class":3774,"line":4892},[3772,15146,15147],{"class":3941},"    try",[3772,15149,4002],{"class":3945},[3772,15151,15152],{"class":3774,"line":4903},[3772,15153,15154],{"class":3934},"        \u002F\u002F 3️⃣ Відправляємо запит на сервер\n",[3772,15156,15157,15159,15162,15164,15167,15170,15172,15175,15177,15180,15183,15185,15187,15190],{"class":3774,"line":4909},[3772,15158,10557],{"class":3980},[3772,15160,15161],{"class":3984}," response",[3772,15163,3988],{"class":3945},[3772,15165,15166],{"class":3941},"await",[3772,15168,15169],{"class":3949}," apiClient",[3772,15171,4059],{"class":3945},[3772,15173,15174],{"class":3778},"post",[3772,15176,5150],{"class":3945},[3772,15178,15179],{"class":3781},"`\u002Ftrips\u002F",[3772,15181,15182],{"class":3980},"${",[3772,15184,7598],{"class":3949},[3772,15186,4235],{"class":3980},[3772,15188,15189],{"class":3781},"\u002Flike`",[3772,15191,15192],{"class":3945},", {\n",[3772,15194,15195,15198,15200,15202],{"class":3774,"line":5521},[3772,15196,15197],{"class":3949},"            liked:",[3772,15199,10699],{"class":3945},[3772,15201,15061],{"class":3949},[3772,15203,4806],{"class":3945},[3772,15205,15206],{"class":3774,"line":5527},[3772,15207,14303],{"class":3945},[3772,15209,15210],{"class":3774,"line":5533},[3772,15211,3965],{"emptyLinePlaceholder":3964},[3772,15213,15214],{"class":3774,"line":5539},[3772,15215,15216],{"class":3934},"        \u002F\u002F 4️⃣ Успіх — повертаємо нові дані\n",[3772,15218,15219,15221],{"class":3774,"line":5545},[3772,15220,5202],{"class":3941},[3772,15222,4002],{"class":3945},[3772,15224,15225,15228],{"class":3774,"line":5550},[3772,15226,15227],{"class":3949},"            tripId",[3772,15229,4806],{"class":3945},[3772,15231,15232,15235,15237,15239,15241,15243,15246],{"class":3774,"line":6121},[3772,15233,15234],{"class":3949},"            isLiked:",[3772,15236,15161],{"class":3949},[3772,15238,4059],{"class":3945},[3772,15240,8198],{"class":3949},[3772,15242,4059],{"class":3945},[3772,15244,15245],{"class":3949},"liked",[3772,15247,4806],{"class":3945},[3772,15249,15250],{"class":3774,"line":6131},[3772,15251,5245],{"class":3945},[3772,15253,15254,15257,15260,15262,15264],{"class":3774,"line":6136},[3772,15255,15256],{"class":3945},"    } ",[3772,15258,15259],{"class":3941},"catch",[3772,15261,5179],{"class":3945},[3772,15263,5072],{"class":3949},[3772,15265,5166],{"class":3945},[3772,15267,15268],{"class":3774,"line":6142},[3772,15269,15270],{"class":3934},"        \u002F\u002F 5️⃣ Помилка — повертаємо дані для rollback\n",[3772,15272,15273,15275,15278],{"class":3774,"line":6150},[3772,15274,5202],{"class":3941},[3772,15276,15277],{"class":3778}," rejectWithValue",[3772,15279,3993],{"class":3945},[3772,15281,15282,15284],{"class":3774,"line":6157},[3772,15283,15227],{"class":3949},[3772,15285,4806],{"class":3945},[3772,15287,15288,15291],{"class":3774,"line":6162},[3772,15289,15290],{"class":3949},"            previousState",[3772,15292,4806],{"class":3945},[3772,15294,15295],{"class":3774,"line":6629},[3772,15296,14303],{"class":3945},[3772,15298,15299],{"class":3774,"line":6653},[3772,15300,4906],{"class":3945},[3772,15302,15303],{"class":3774,"line":6698},[3772,15304,4020],{"class":3945},[3747,15306,15308],{"id":15307},"крок-4-slice-обробляє-дії-в-extrareducers","Крок 4: Slice обробляє дії в extraReducers",[3762,15310,15312],{"className":3925,"code":15311,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FlikesSlice.ts\nimport { createSlice, PayloadAction } from '@reduxjs\u002Ftoolkit'\nimport { toggleLikeThunk } from '..\u002Fthunks\u002FlikesThunks'\n\ninterface LikesState {\n    byTripId: Record\u003Cstring, boolean> \u002F\u002F { '123': true, '456': false }\n    loading: boolean\n    error: string | null\n}\n\nconst initialState: LikesState = {\n    byTripId: {},\n    loading: false,\n    error: null,\n}\n\nexport const likesSlice = createSlice({\n    name: 'likes',\n    initialState,\n    reducers: {\n        \u002F\u002F Внутрішні дії (якщо потрібні)\n    },\n    extraReducers: (builder) => {\n        builder\n            \u002F\u002F 1️⃣ PENDING: Оптимістичне оновлення UI\n            .addCase(toggleLikeThunk.pending, (state, action) => {\n                const { tripId } = action.meta.arg\n                const currentState = state.byTripId[tripId] ?? false\n\n                \u002F\u002F Миттєво змінюємо UI (не чекаємо сервер!)\n                state.byTripId[tripId] = !currentState\n                state.loading = true\n                state.error = null\n\n                console.log('🟡 PENDING: UI оновлено миттєво')\n            })\n\n            \u002F\u002F 2️⃣ FULFILLED: Фіксуємо результат від сервера\n            .addCase(toggleLikeThunk.fulfilled, (state, action) => {\n                const { tripId, isLiked } = action.payload\n\n                \u002F\u002F Встановлюємо точний стан від сервера\n                state.byTripId[tripId] = isLiked\n                state.loading = false\n\n                console.log('🟢 FULFILLED: Сервер підтвердив:', isLiked)\n            })\n\n            \u002F\u002F 3️⃣ REJECTED: Відкат до попереднього стану\n            .addCase(toggleLikeThunk.rejected, (state, action) => {\n                if (action.payload) {\n                    const { tripId, previousState } = action.payload\n\n                    \u002F\u002F ROLLBACK: повертаємо попереднє значення\n                    state.byTripId[tripId] = previousState\n                    state.loading = false\n                    state.error = 'Не вдалося оновити лайк'\n\n                    console.log('🔴 REJECTED: Повернуто до:', previousState)\n                }\n            })\n    },\n})\n\nexport default likesSlice.reducer\n",[3769,15313,15314,15319,15337,15352,15356,15365,15389,15397,15409,15413,15417,15430,15437,15445,15453,15457,15461,15476,15485,15491,15497,15502,15506,15522,15526,15531,15559,15581,15604,15608,15613,15631,15643,15655,15659,15675,15679,15683,15688,15716,15736,15740,15745,15762,15774,15778,15797,15801,15805,15810,15838,15853,15874,15878,15883,15900,15912,15925,15929,15949,15953,15957,15961,15965,15969],{"__ignoreMap":3767},[3772,15315,15316],{"class":3774,"line":3775},[3772,15317,15318],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fslices\u002FlikesSlice.ts\n",[3772,15320,15321,15323,15325,15327,15329,15331,15333,15335],{"class":3774,"line":3938},[3772,15322,3942],{"class":3941},[3772,15324,3946],{"class":3945},[3772,15326,3846],{"class":3949},[3772,15328,3847],{"class":3945},[3772,15330,6361],{"class":3949},[3772,15332,3952],{"class":3945},[3772,15334,3955],{"class":3941},[3772,15336,3958],{"class":3781},[3772,15338,15339,15341,15343,15345,15347,15349],{"class":3774,"line":3961},[3772,15340,3942],{"class":3941},[3772,15342,3946],{"class":3945},[3772,15344,14557],{"class":3949},[3772,15346,3952],{"class":3945},[3772,15348,3955],{"class":3941},[3772,15350,15351],{"class":3781}," '..\u002Fthunks\u002FlikesThunks'\n",[3772,15353,15354],{"class":3774,"line":3968},[3772,15355,3965],{"emptyLinePlaceholder":3964},[3772,15357,15358,15360,15363],{"class":3774,"line":3974},[3772,15359,6376],{"class":3980},[3772,15361,15362],{"class":4042}," LikesState",[3772,15364,4002],{"class":3945},[3772,15366,15367,15370,15372,15375,15377,15379,15381,15383,15386],{"class":3774,"line":3996},[3772,15368,15369],{"class":3949},"    byTripId",[3772,15371,4800],{"class":3945},[3772,15373,15374],{"class":4042},"Record",[3772,15376,4051],{"class":3945},[3772,15378,6459],{"class":4042},[3772,15380,3847],{"class":3945},[3772,15382,6729],{"class":4042},[3772,15384,15385],{"class":3945},"> ",[3772,15387,15388],{"class":3934},"\u002F\u002F { '123': true, '456': false }\n",[3772,15390,15391,15393,15395],{"class":3774,"line":4005},[3772,15392,6444],{"class":3949},[3772,15394,4800],{"class":3945},[3772,15396,6449],{"class":4042},[3772,15398,15399,15401,15403,15405,15407],{"class":3774,"line":4011},[3772,15400,6454],{"class":3949},[3772,15402,4800],{"class":3945},[3772,15404,6459],{"class":4042},[3772,15406,6462],{"class":3945},[3772,15408,4816],{"class":4042},[3772,15410,15411],{"class":3774,"line":4017},[3772,15412,4316],{"class":3945},[3772,15414,15415],{"class":3774,"line":4023},[3772,15416,3965],{"emptyLinePlaceholder":3964},[3772,15418,15419,15421,15423,15425,15428],{"class":3774,"line":4028},[3772,15420,5885],{"class":3980},[3772,15422,5888],{"class":3984},[3772,15424,4800],{"class":3945},[3772,15426,15427],{"class":4042},"LikesState",[3772,15429,5891],{"class":3945},[3772,15431,15432,15435],{"class":3774,"line":4034},[3772,15433,15434],{"class":3949},"    byTripId:",[3772,15436,12632],{"class":3945},[3772,15438,15439,15441,15443],{"class":3774,"line":4068},[3772,15440,5903],{"class":3949},[3772,15442,4279],{"class":3980},[3772,15444,4806],{"class":3945},[3772,15446,15447,15449,15451],{"class":3774,"line":4313},[3772,15448,5912],{"class":3949},[3772,15450,5915],{"class":3980},[3772,15452,4806],{"class":3945},[3772,15454,15455],{"class":3774,"line":4470},[3772,15456,4316],{"class":3945},[3772,15458,15459],{"class":3774,"line":4879},[3772,15460,3965],{"emptyLinePlaceholder":3964},[3772,15462,15463,15465,15467,15470,15472,15474],{"class":3774,"line":4892},[3772,15464,3977],{"class":3941},[3772,15466,3981],{"class":3980},[3772,15468,15469],{"class":3984}," likesSlice",[3772,15471,3988],{"class":3945},[3772,15473,3846],{"class":3778},[3772,15475,3993],{"class":3945},[3772,15477,15478,15480,15483],{"class":3774,"line":4903},[3772,15479,6540],{"class":3949},[3772,15481,15482],{"class":3781}," 'likes'",[3772,15484,4806],{"class":3945},[3772,15486,15487,15489],{"class":3774,"line":4909},[3772,15488,6550],{"class":3949},[3772,15490,4806],{"class":3945},[3772,15492,15493,15495],{"class":3774,"line":5521},[3772,15494,6557],{"class":3949},[3772,15496,4002],{"class":3945},[3772,15498,15499],{"class":3774,"line":5527},[3772,15500,15501],{"class":3934},"        \u002F\u002F Внутрішні дії (якщо потрібні)\n",[3772,15503,15504],{"class":3774,"line":5533},[3772,15505,4014],{"class":3945},[3772,15507,15508,15510,15512,15514,15516,15518,15520],{"class":3774,"line":5539},[3772,15509,9190],{"class":3778},[3772,15511,4094],{"class":3949},[3772,15513,5179],{"class":3945},[3772,15515,9197],{"class":3949},[3772,15517,5765],{"class":3945},[3772,15519,5768],{"class":3980},[3772,15521,4002],{"class":3945},[3772,15523,15524],{"class":3774,"line":5545},[3772,15525,9215],{"class":3949},[3772,15527,15528],{"class":3774,"line":5550},[3772,15529,15530],{"class":3934},"            \u002F\u002F 1️⃣ PENDING: Оптимістичне оновлення UI\n",[3772,15532,15533,15535,15537,15539,15541,15543,15545,15547,15549,15551,15553,15555,15557],{"class":3774,"line":6121},[3772,15534,9221],{"class":3945},[3772,15536,9224],{"class":3778},[3772,15538,5150],{"class":3945},[3772,15540,14557],{"class":3949},[3772,15542,4059],{"class":3945},[3772,15544,9234],{"class":3949},[3772,15546,7128],{"class":3945},[3772,15548,5153],{"class":3949},[3772,15550,3847],{"class":3945},[3772,15552,5163],{"class":3949},[3772,15554,5765],{"class":3945},[3772,15556,5768],{"class":3980},[3772,15558,4002],{"class":3945},[3772,15560,15561,15564,15566,15568,15570,15572,15574,15576,15578],{"class":3774,"line":6131},[3772,15562,15563],{"class":3980},"                const",[3772,15565,3946],{"class":3945},[3772,15567,7598],{"class":3984},[3772,15569,6801],{"class":3945},[3772,15571,5163],{"class":3949},[3772,15573,4059],{"class":3945},[3772,15575,5067],{"class":3949},[3772,15577,4059],{"class":3945},[3772,15579,15580],{"class":3949},"arg\n",[3772,15582,15583,15585,15588,15590,15592,15594,15596,15598,15600,15602],{"class":3774,"line":6136},[3772,15584,15563],{"class":3980},[3772,15586,15587],{"class":3984}," currentState",[3772,15589,3988],{"class":3945},[3772,15591,5153],{"class":3949},[3772,15593,4059],{"class":3945},[3772,15595,14645],{"class":3949},[3772,15597,10793],{"class":3945},[3772,15599,7598],{"class":3949},[3772,15601,14652],{"class":3945},[3772,15603,9324],{"class":3980},[3772,15605,15606],{"class":3774,"line":6142},[3772,15607,3965],{"emptyLinePlaceholder":3964},[3772,15609,15610],{"class":3774,"line":6150},[3772,15611,15612],{"class":3934},"                \u002F\u002F Миттєво змінюємо UI (не чекаємо сервер!)\n",[3772,15614,15615,15617,15619,15621,15623,15625,15628],{"class":3774,"line":6157},[3772,15616,8815],{"class":3949},[3772,15618,4059],{"class":3945},[3772,15620,14645],{"class":3949},[3772,15622,10793],{"class":3945},[3772,15624,7598],{"class":3949},[3772,15626,15627],{"class":3945},"] = !",[3772,15629,15630],{"class":3949},"currentState\n",[3772,15632,15633,15635,15637,15639,15641],{"class":3774,"line":6162},[3772,15634,8815],{"class":3949},[3772,15636,4059],{"class":3945},[3772,15638,6741],{"class":3949},[3772,15640,3988],{"class":3945},[3772,15642,4865],{"class":3980},[3772,15644,15645,15647,15649,15651,15653],{"class":3774,"line":6629},[3772,15646,8815],{"class":3949},[3772,15648,4059],{"class":3945},[3772,15650,5072],{"class":3949},[3772,15652,3988],{"class":3945},[3772,15654,4816],{"class":3980},[3772,15656,15657],{"class":3774,"line":6653},[3772,15658,3965],{"emptyLinePlaceholder":3964},[3772,15660,15661,15664,15666,15668,15670,15673],{"class":3774,"line":6698},[3772,15662,15663],{"class":3949},"                console",[3772,15665,4059],{"class":3945},[3772,15667,7289],{"class":3778},[3772,15669,5150],{"class":3945},[3772,15671,15672],{"class":3781},"'🟡 PENDING: UI оновлено миттєво'",[3772,15674,5345],{"class":3945},[3772,15676,15677],{"class":3774,"line":6703},[3772,15678,9263],{"class":3945},[3772,15680,15681],{"class":3774,"line":6709},[3772,15682,3965],{"emptyLinePlaceholder":3964},[3772,15684,15685],{"class":3774,"line":6734},[3772,15686,15687],{"class":3934},"            \u002F\u002F 2️⃣ FULFILLED: Фіксуємо результат від сервера\n",[3772,15689,15690,15692,15694,15696,15698,15700,15702,15704,15706,15708,15710,15712,15714],{"class":3774,"line":6753},[3772,15691,9221],{"class":3945},[3772,15693,9224],{"class":3778},[3772,15695,5150],{"class":3945},[3772,15697,14557],{"class":3949},[3772,15699,4059],{"class":3945},[3772,15701,9279],{"class":3949},[3772,15703,7128],{"class":3945},[3772,15705,5153],{"class":3949},[3772,15707,3847],{"class":3945},[3772,15709,5163],{"class":3949},[3772,15711,5765],{"class":3945},[3772,15713,5768],{"class":3980},[3772,15715,4002],{"class":3945},[3772,15717,15718,15720,15722,15724,15726,15728,15730,15732,15734],{"class":3774,"line":6758},[3772,15719,15563],{"class":3980},[3772,15721,3946],{"class":3945},[3772,15723,7598],{"class":3984},[3772,15725,3847],{"class":3945},[3772,15727,14785],{"class":3984},[3772,15729,6801],{"class":3945},[3772,15731,5163],{"class":3949},[3772,15733,4059],{"class":3945},[3772,15735,6750],{"class":3949},[3772,15737,15738],{"class":3774,"line":6763},[3772,15739,3965],{"emptyLinePlaceholder":3964},[3772,15741,15742],{"class":3774,"line":6768},[3772,15743,15744],{"class":3934},"                \u002F\u002F Встановлюємо точний стан від сервера\n",[3772,15746,15747,15749,15751,15753,15755,15757,15759],{"class":3774,"line":6773},[3772,15748,8815],{"class":3949},[3772,15750,4059],{"class":3945},[3772,15752,14645],{"class":3949},[3772,15754,10793],{"class":3945},[3772,15756,7598],{"class":3949},[3772,15758,10798],{"class":3945},[3772,15760,15761],{"class":3949},"isLiked\n",[3772,15763,15764,15766,15768,15770,15772],{"class":3774,"line":6779},[3772,15765,8815],{"class":3949},[3772,15767,4059],{"class":3945},[3772,15769,6741],{"class":3949},[3772,15771,3988],{"class":3945},[3772,15773,9324],{"class":3980},[3772,15775,15776],{"class":3774,"line":6812},[3772,15777,3965],{"emptyLinePlaceholder":3964},[3772,15779,15780,15782,15784,15786,15788,15791,15793,15795],{"class":3774,"line":6817},[3772,15781,15663],{"class":3949},[3772,15783,4059],{"class":3945},[3772,15785,7289],{"class":3778},[3772,15787,5150],{"class":3945},[3772,15789,15790],{"class":3781},"'🟢 FULFILLED: Сервер підтвердив:'",[3772,15792,3847],{"class":3945},[3772,15794,14785],{"class":3949},[3772,15796,5345],{"class":3945},[3772,15798,15799],{"class":3774,"line":6823},[3772,15800,9263],{"class":3945},[3772,15802,15803],{"class":3774,"line":8841},[3772,15804,3965],{"emptyLinePlaceholder":3964},[3772,15806,15807],{"class":3774,"line":8865},[3772,15808,15809],{"class":3934},"            \u002F\u002F 3️⃣ REJECTED: Відкат до попереднього стану\n",[3772,15811,15812,15814,15816,15818,15820,15822,15824,15826,15828,15830,15832,15834,15836],{"class":3774,"line":8873},[3772,15813,9221],{"class":3945},[3772,15815,9224],{"class":3778},[3772,15817,5150],{"class":3945},[3772,15819,14557],{"class":3949},[3772,15821,4059],{"class":3945},[3772,15823,12260],{"class":3949},[3772,15825,7128],{"class":3945},[3772,15827,5153],{"class":3949},[3772,15829,3847],{"class":3945},[3772,15831,5163],{"class":3949},[3772,15833,5765],{"class":3945},[3772,15835,5768],{"class":3980},[3772,15837,4002],{"class":3945},[3772,15839,15840,15843,15845,15847,15849,15851],{"class":3774,"line":8881},[3772,15841,15842],{"class":3941},"                if",[3772,15844,5179],{"class":3945},[3772,15846,5163],{"class":3949},[3772,15848,4059],{"class":3945},[3772,15850,5059],{"class":3949},[3772,15852,5166],{"class":3945},[3772,15854,15855,15858,15860,15862,15864,15866,15868,15870,15872],{"class":3774,"line":8894},[3772,15856,15857],{"class":3980},"                    const",[3772,15859,3946],{"class":3945},[3772,15861,7598],{"class":3984},[3772,15863,3847],{"class":3945},[3772,15865,15061],{"class":3984},[3772,15867,6801],{"class":3945},[3772,15869,5163],{"class":3949},[3772,15871,4059],{"class":3945},[3772,15873,6750],{"class":3949},[3772,15875,15876],{"class":3774,"line":8902},[3772,15877,3965],{"emptyLinePlaceholder":3964},[3772,15879,15880],{"class":3774,"line":8910},[3772,15881,15882],{"class":3934},"                    \u002F\u002F ROLLBACK: повертаємо попереднє значення\n",[3772,15884,15885,15887,15889,15891,15893,15895,15897],{"class":3774,"line":8922},[3772,15886,12978],{"class":3949},[3772,15888,4059],{"class":3945},[3772,15890,14645],{"class":3949},[3772,15892,10793],{"class":3945},[3772,15894,7598],{"class":3949},[3772,15896,10798],{"class":3945},[3772,15898,15899],{"class":3949},"previousState\n",[3772,15901,15902,15904,15906,15908,15910],{"class":3774,"line":8928},[3772,15903,12978],{"class":3949},[3772,15905,4059],{"class":3945},[3772,15907,6741],{"class":3949},[3772,15909,3988],{"class":3945},[3772,15911,9324],{"class":3980},[3772,15913,15914,15916,15918,15920,15922],{"class":3774,"line":8934},[3772,15915,12978],{"class":3949},[3772,15917,4059],{"class":3945},[3772,15919,5072],{"class":3949},[3772,15921,3988],{"class":3945},[3772,15923,15924],{"class":3781},"'Не вдалося оновити лайк'\n",[3772,15926,15927],{"class":3774,"line":8939},[3772,15928,3965],{"emptyLinePlaceholder":3964},[3772,15930,15931,15934,15936,15938,15940,15943,15945,15947],{"class":3774,"line":8944},[3772,15932,15933],{"class":3949},"                    console",[3772,15935,4059],{"class":3945},[3772,15937,7289],{"class":3778},[3772,15939,5150],{"class":3945},[3772,15941,15942],{"class":3781},"'🔴 REJECTED: Повернуто до:'",[3772,15944,3847],{"class":3945},[3772,15946,15061],{"class":3949},[3772,15948,5345],{"class":3945},[3772,15950,15951],{"class":3774,"line":8949},[3772,15952,8931],{"class":3945},[3772,15954,15955],{"class":3774,"line":8955},[3772,15956,9263],{"class":3945},[3772,15958,15959],{"class":3774,"line":8992},[3772,15960,4014],{"class":3945},[3772,15962,15963],{"class":3774,"line":9040},[3772,15964,4020],{"class":3945},[3772,15966,15967],{"class":3774,"line":9052},[3772,15968,3965],{"emptyLinePlaceholder":3964},[3772,15970,15971,15973,15975,15977,15979],{"class":3774,"line":9077},[3772,15972,3977],{"class":3941},[3772,15974,4196],{"class":3941},[3772,15976,15469],{"class":3949},[3772,15978,4059],{"class":3945},[3772,15980,6834],{"class":3949},[3747,15982,15984],{"id":15983},"крок-5-компонент-ререндериться-автоматично","Крок 5: Компонент ререндериться автоматично",[3762,15986,15988],{"className":4129,"code":15987,"language":4131,"meta":3767,"style":3767},"\u002F\u002F React автоматично виявляє зміни в store через useAppSelector\nexport function TripCard({ tripId }: { tripId: string }) {\n    \u002F\u002F 6️⃣ Цей селектор підписаний на зміни в state.likes.byTripId\n    const isLiked = useAppSelector((state) => state.likes.byTripId[tripId] ?? false)\n\n    \u002F\u002F 7️⃣ Коли state.likes.byTripId[tripId] змінюється:\n    \u002F\u002F    - React виявляє зміну (нове посилання)\n    \u002F\u002F    - Компонент ререндериться\n    \u002F\u002F    - UI оновлюється (❤️ або 🤍)\n\n    return \u003CText>{isLiked ? '❤️ Лайкнуто' : '🤍 Лайкнути'}\u003C\u002FText>\n}\n",[3769,15989,15990,15995,16017,16022,16060,16064,16069,16074,16079,16084,16088,16121],{"__ignoreMap":3767},[3772,15991,15992],{"class":3774,"line":3775},[3772,15993,15994],{"class":3934},"\u002F\u002F React автоматично виявляє зміни в store через useAppSelector\n",[3772,15996,15997,15999,16001,16003,16005,16007,16009,16011,16013,16015],{"class":3774,"line":3938},[3772,15998,3977],{"class":3941},[3772,16000,4199],{"class":3980},[3772,16002,14577],{"class":3778},[3772,16004,10074],{"class":3945},[3772,16006,7598],{"class":3949},[3772,16008,14584],{"class":3945},[3772,16010,7598],{"class":3949},[3772,16012,4800],{"class":3945},[3772,16014,6459],{"class":4042},[3772,16016,14593],{"class":3945},[3772,16018,16019],{"class":3774,"line":3961},[3772,16020,16021],{"class":3934},"    \u002F\u002F 6️⃣ Цей селектор підписаний на зміни в state.likes.byTripId\n",[3772,16023,16024,16026,16028,16030,16032,16034,16036,16038,16040,16042,16044,16046,16048,16050,16052,16054,16056,16058],{"class":3774,"line":3968},[3772,16025,10944],{"class":3980},[3772,16027,14622],{"class":3984},[3772,16029,3988],{"class":3945},[3772,16031,10952],{"class":3778},[3772,16033,6056],{"class":3945},[3772,16035,5153],{"class":3949},[3772,16037,5765],{"class":3945},[3772,16039,5768],{"class":3980},[3772,16041,5353],{"class":3949},[3772,16043,4059],{"class":3945},[3772,16045,8983],{"class":3949},[3772,16047,4059],{"class":3945},[3772,16049,14645],{"class":3949},[3772,16051,10793],{"class":3945},[3772,16053,7598],{"class":3949},[3772,16055,14652],{"class":3945},[3772,16057,4803],{"class":3980},[3772,16059,5345],{"class":3945},[3772,16061,16062],{"class":3774,"line":3974},[3772,16063,3965],{"emptyLinePlaceholder":3964},[3772,16065,16066],{"class":3774,"line":3996},[3772,16067,16068],{"class":3934},"    \u002F\u002F 7️⃣ Коли state.likes.byTripId[tripId] змінюється:\n",[3772,16070,16071],{"class":3774,"line":4005},[3772,16072,16073],{"class":3934},"    \u002F\u002F    - React виявляє зміну (нове посилання)\n",[3772,16075,16076],{"class":3774,"line":4011},[3772,16077,16078],{"class":3934},"    \u002F\u002F    - Компонент ререндериться\n",[3772,16080,16081],{"class":3774,"line":4017},[3772,16082,16083],{"class":3934},"    \u002F\u002F    - UI оновлюється (❤️ або 🤍)\n",[3772,16085,16086],{"class":3774,"line":4023},[3772,16087,3965],{"emptyLinePlaceholder":3964},[3772,16089,16090,16092,16095,16097,16099,16101,16103,16105,16108,16110,16113,16115,16117,16119],{"class":3774,"line":4028},[3772,16091,4210],{"class":3941},[3772,16093,16094],{"class":4218}," \u003C",[3772,16096,14521],{"class":4042},[3772,16098,14780],{"class":4218},[3772,16100,4230],{"class":3980},[3772,16102,14785],{"class":3949},[3772,16104,14788],{"class":3945},[3772,16106,16107],{"class":3781}," '❤️ Лайкнуто'",[3772,16109,14794],{"class":3945},[3772,16111,16112],{"class":3781}," '🤍 Лайкнути'",[3772,16114,4235],{"class":3980},[3772,16116,14802],{"class":4218},[3772,16118,14521],{"class":4042},[3772,16120,4065],{"class":4218},[3772,16122,16123],{"class":3774,"line":4034},[3772,16124,4316],{"class":3945},[3747,16126,16128],{"id":16127},"візуалізація-повного-циклу","Візуалізація повного циклу",[5417,16130,16132],{"alt":16131},"Повний цикл Redux операції",[3762,16133,16135],{"className":5422,"code":16134,"language":5424,"meta":3767,"style":3767},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam defaultFontName \"Helvetica\"\n\nactor \"Користувач\" as User #DBEAFE\nparticipant \"TripCard\\nКомпонент\" as Component #FEF08A\nparticipant \"dispatch()\" as Dispatch #FED7AA\nparticipant \"toggleLikeThunk\" as Thunk #DCFCE7\nparticipant \"HTTP API\" as API #E0E7FF\nparticipant \"likesSlice\\nextraReducers\" as Reducer #FEF3C7\ndatabase \"Redux Store\" as Store #E0E7FF\nparticipant \"useAppSelector\" as Selector #FED7AA\n\nUser -> Component : 1. Натискає кнопку ❤️\nComponent -> Dispatch : 2. dispatch(toggleLikeThunk({ tripId: '123' }))\n\nDispatch -> Reducer : 3. Відправка PENDING дії\nnote right\n    type: 'likes\u002FtoggleLike\u002Fpending'\n    meta: { arg: { tripId: '123' } }\nend note\n\nReducer -> Reducer : 4. Оптимістичне оновлення\\nstate.byTripId['123'] = true\nReducer -> Store : 5. Збереження нового стану\nStore -> Selector : 6. Сповіщення підписників\nSelector -> Component : 7. isLiked = true\nComponent -> User : 8. UI оновлено миттєво! ❤️\n\nThunk -> API : 9. await POST \u002Ftrips\u002F123\u002Flike\nAPI --> Thunk : 10. Відповідь: { liked: true }\n\nThunk -> Reducer : 11. Відправка FULFILLED дії\nnote right\n    type: 'likes\u002FtoggleLike\u002Ffulfilled'\n    payload: { tripId: '123', isLiked: true }\nend note\n\nReducer -> Store : 12. Фіксація результату від сервера\nStore -> Selector : 13. Перевірка змін (посилання те саме)\nSelector -> Component : 14. Компонент НЕ ререндериться\\n(стан не змінився)\n\nnote over Component, User #d1fae5\n    Користувач бачить миттєву реакцію UI!\n    Затримка мережі непомітна.\nend note\n\n@enduml\n",[3769,16136,16137,16141,16145,16149,16153,16157,16161,16166,16171,16176,16181,16186,16191,16196,16200,16205,16210,16214,16219,16224,16229,16234,16238,16242,16247,16252,16257,16262,16267,16271,16276,16281,16285,16290,16294,16299,16304,16308,16312,16317,16322,16327,16331,16336,16341,16346,16350,16354],{"__ignoreMap":3767},[3772,16138,16139],{"class":3774,"line":3775},[3772,16140,5431],{},[3772,16142,16143],{"class":3774,"line":3938},[3772,16144,5436],{},[3772,16146,16147],{"class":3774,"line":3961},[3772,16148,5441],{},[3772,16150,16151],{"class":3774,"line":3968},[3772,16152,5446],{},[3772,16154,16155],{"class":3774,"line":3974},[3772,16156,3965],{"emptyLinePlaceholder":3964},[3772,16158,16159],{"class":3774,"line":3996},[3772,16160,5455],{},[3772,16162,16163],{"class":3774,"line":4005},[3772,16164,16165],{},"participant \"TripCard\\nКомпонент\" as Component #FEF08A\n",[3772,16167,16168],{"class":3774,"line":4011},[3772,16169,16170],{},"participant \"dispatch()\" as Dispatch #FED7AA\n",[3772,16172,16173],{"class":3774,"line":4017},[3772,16174,16175],{},"participant \"toggleLikeThunk\" as Thunk #DCFCE7\n",[3772,16177,16178],{"class":3774,"line":4023},[3772,16179,16180],{},"participant \"HTTP API\" as API #E0E7FF\n",[3772,16182,16183],{"class":3774,"line":4028},[3772,16184,16185],{},"participant \"likesSlice\\nextraReducers\" as Reducer #FEF3C7\n",[3772,16187,16188],{"class":3774,"line":4034},[3772,16189,16190],{},"database \"Redux Store\" as Store #E0E7FF\n",[3772,16192,16193],{"class":3774,"line":4068},[3772,16194,16195],{},"participant \"useAppSelector\" as Selector #FED7AA\n",[3772,16197,16198],{"class":3774,"line":4313},[3772,16199,3965],{"emptyLinePlaceholder":3964},[3772,16201,16202],{"class":3774,"line":4470},[3772,16203,16204],{},"User -> Component : 1. Натискає кнопку ❤️\n",[3772,16206,16207],{"class":3774,"line":4879},[3772,16208,16209],{},"Component -> Dispatch : 2. dispatch(toggleLikeThunk({ tripId: '123' }))\n",[3772,16211,16212],{"class":3774,"line":4892},[3772,16213,3965],{"emptyLinePlaceholder":3964},[3772,16215,16216],{"class":3774,"line":4903},[3772,16217,16218],{},"Dispatch -> Reducer : 3. Відправка PENDING дії\n",[3772,16220,16221],{"class":3774,"line":4909},[3772,16222,16223],{},"note right\n",[3772,16225,16226],{"class":3774,"line":5521},[3772,16227,16228],{},"    type: 'likes\u002FtoggleLike\u002Fpending'\n",[3772,16230,16231],{"class":3774,"line":5527},[3772,16232,16233],{},"    meta: { arg: { tripId: '123' } }\n",[3772,16235,16236],{"class":3774,"line":5533},[3772,16237,5542],{},[3772,16239,16240],{"class":3774,"line":5539},[3772,16241,3965],{"emptyLinePlaceholder":3964},[3772,16243,16244],{"class":3774,"line":5545},[3772,16245,16246],{},"Reducer -> Reducer : 4. Оптимістичне оновлення\\nstate.byTripId['123'] = true\n",[3772,16248,16249],{"class":3774,"line":5550},[3772,16250,16251],{},"Reducer -> Store : 5. Збереження нового стану\n",[3772,16253,16254],{"class":3774,"line":6121},[3772,16255,16256],{},"Store -> Selector : 6. Сповіщення підписників\n",[3772,16258,16259],{"class":3774,"line":6131},[3772,16260,16261],{},"Selector -> Component : 7. isLiked = true\n",[3772,16263,16264],{"class":3774,"line":6136},[3772,16265,16266],{},"Component -> User : 8. UI оновлено миттєво! ❤️\n",[3772,16268,16269],{"class":3774,"line":6142},[3772,16270,3965],{"emptyLinePlaceholder":3964},[3772,16272,16273],{"class":3774,"line":6150},[3772,16274,16275],{},"Thunk -> API : 9. await POST \u002Ftrips\u002F123\u002Flike\n",[3772,16277,16278],{"class":3774,"line":6157},[3772,16279,16280],{},"API --> Thunk : 10. Відповідь: { liked: true }\n",[3772,16282,16283],{"class":3774,"line":6162},[3772,16284,3965],{"emptyLinePlaceholder":3964},[3772,16286,16287],{"class":3774,"line":6629},[3772,16288,16289],{},"Thunk -> Reducer : 11. Відправка FULFILLED дії\n",[3772,16291,16292],{"class":3774,"line":6653},[3772,16293,16223],{},[3772,16295,16296],{"class":3774,"line":6698},[3772,16297,16298],{},"    type: 'likes\u002FtoggleLike\u002Ffulfilled'\n",[3772,16300,16301],{"class":3774,"line":6703},[3772,16302,16303],{},"    payload: { tripId: '123', isLiked: true }\n",[3772,16305,16306],{"class":3774,"line":6709},[3772,16307,5542],{},[3772,16309,16310],{"class":3774,"line":6734},[3772,16311,3965],{"emptyLinePlaceholder":3964},[3772,16313,16314],{"class":3774,"line":6753},[3772,16315,16316],{},"Reducer -> Store : 12. Фіксація результату від сервера\n",[3772,16318,16319],{"class":3774,"line":6758},[3772,16320,16321],{},"Store -> Selector : 13. Перевірка змін (посилання те саме)\n",[3772,16323,16324],{"class":3774,"line":6763},[3772,16325,16326],{},"Selector -> Component : 14. Компонент НЕ ререндериться\\n(стан не змінився)\n",[3772,16328,16329],{"class":3774,"line":6768},[3772,16330,3965],{"emptyLinePlaceholder":3964},[3772,16332,16333],{"class":3774,"line":6773},[3772,16334,16335],{},"note over Component, User #d1fae5\n",[3772,16337,16338],{"class":3774,"line":6779},[3772,16339,16340],{},"    Користувач бачить миттєву реакцію UI!\n",[3772,16342,16343],{"class":3774,"line":6812},[3772,16344,16345],{},"    Затримка мережі непомітна.\n",[3772,16347,16348],{"class":3774,"line":6817},[3772,16349,5542],{},[3772,16351,16352],{"class":3774,"line":6823},[3772,16353,3965],{"emptyLinePlaceholder":3964},[3772,16355,16356],{"class":3774,"line":8841},[3772,16357,5553],{},[3747,16359,16361],{"id":16360},"типові-помилки-та-їх-вирішення","Типові помилки та їх вирішення",[10844,16363,16364,16548,16718],{},[10847,16365,16368,16374],{"icon":16366,"title":16367},"i-lucide-alert-circle","Помилка: Компонент не ререндериться після dispatch",[3743,16369,16370,16373],{},[3829,16371,16372],{},"Причина:"," Селектор повертає той самий об'єкт за посиланням.",[3762,16375,16377],{"className":3925,"code":16376,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОГАНО: Створює новий масив при кожному виклику\nconst trips = useAppSelector((state) => state.trips.items.filter((t) => t.region === 'Захід'))\n\u002F\u002F Компонент ререндериться навіть якщо дані не змінились!\n\n\u002F\u002F ✅ ДОБРЕ: Використовуйте мемоїзований селектор\nconst selectWesternTrips = createSelector([(state) => state.trips.items], (items) =>\n    items.filter((t) => t.region === 'Захід'),\n)\n\nconst trips = useAppSelector(selectWesternTrips)\n\u002F\u002F Компонент ререндериться тільки якщо результат дійсно змінився\n",[3769,16378,16379,16384,16436,16441,16445,16450,16490,16518,16522,16526,16543],{"__ignoreMap":3767},[3772,16380,16381],{"class":3774,"line":3775},[3772,16382,16383],{"class":3934},"\u002F\u002F ❌ ПОГАНО: Створює новий масив при кожному виклику\n",[3772,16385,16386,16388,16390,16392,16394,16396,16398,16400,16402,16404,16406,16408,16410,16412,16414,16416,16418,16420,16422,16424,16426,16428,16430,16432,16434],{"class":3774,"line":3938},[3772,16387,5885],{"class":3980},[3772,16389,10947],{"class":3984},[3772,16391,3988],{"class":3945},[3772,16393,10952],{"class":3778},[3772,16395,6056],{"class":3945},[3772,16397,5153],{"class":3949},[3772,16399,5765],{"class":3945},[3772,16401,5768],{"class":3980},[3772,16403,5353],{"class":3949},[3772,16405,4059],{"class":3945},[3772,16407,7557],{"class":3949},[3772,16409,4059],{"class":3945},[3772,16411,5237],{"class":3949},[3772,16413,4059],{"class":3945},[3772,16415,6053],{"class":3778},[3772,16417,6056],{"class":3945},[3772,16419,6059],{"class":3949},[3772,16421,5765],{"class":3945},[3772,16423,5768],{"class":3980},[3772,16425,6066],{"class":3949},[3772,16427,4059],{"class":3945},[3772,16429,7140],{"class":3949},[3772,16431,5188],{"class":3945},[3772,16433,7277],{"class":3781},[3772,16435,10331],{"class":3945},[3772,16437,16438],{"class":3774,"line":3961},[3772,16439,16440],{"class":3934},"\u002F\u002F Компонент ререндериться навіть якщо дані не змінились!\n",[3772,16442,16443],{"class":3774,"line":3968},[3772,16444,3965],{"emptyLinePlaceholder":3964},[3772,16446,16447],{"class":3774,"line":3974},[3772,16448,16449],{"class":3934},"\u002F\u002F ✅ ДОБРЕ: Використовуйте мемоїзований селектор\n",[3772,16451,16452,16454,16457,16459,16462,16465,16467,16469,16471,16473,16475,16477,16479,16481,16484,16486,16488],{"class":3774,"line":3996},[3772,16453,5885],{"class":3980},[3772,16455,16456],{"class":3984}," selectWesternTrips",[3772,16458,3988],{"class":3945},[3772,16460,16461],{"class":3778},"createSelector",[3772,16463,16464],{"class":3945},"([(",[3772,16466,5153],{"class":3949},[3772,16468,5765],{"class":3945},[3772,16470,5768],{"class":3980},[3772,16472,5353],{"class":3949},[3772,16474,4059],{"class":3945},[3772,16476,7557],{"class":3949},[3772,16478,4059],{"class":3945},[3772,16480,5237],{"class":3949},[3772,16482,16483],{"class":3945},"], (",[3772,16485,5237],{"class":3949},[3772,16487,5765],{"class":3945},[3772,16489,11064],{"class":3980},[3772,16491,16492,16494,16496,16498,16500,16502,16504,16506,16508,16510,16512,16514,16516],{"class":3774,"line":4005},[3772,16493,6431],{"class":3949},[3772,16495,4059],{"class":3945},[3772,16497,6053],{"class":3778},[3772,16499,6056],{"class":3945},[3772,16501,6059],{"class":3949},[3772,16503,5765],{"class":3945},[3772,16505,5768],{"class":3980},[3772,16507,6066],{"class":3949},[3772,16509,4059],{"class":3945},[3772,16511,7140],{"class":3949},[3772,16513,5188],{"class":3945},[3772,16515,7277],{"class":3781},[3772,16517,6082],{"class":3945},[3772,16519,16520],{"class":3774,"line":4011},[3772,16521,5345],{"class":3945},[3772,16523,16524],{"class":3774,"line":4017},[3772,16525,3965],{"emptyLinePlaceholder":3964},[3772,16527,16528,16530,16532,16534,16536,16538,16541],{"class":3774,"line":4023},[3772,16529,5885],{"class":3980},[3772,16531,10947],{"class":3984},[3772,16533,3988],{"class":3945},[3772,16535,10952],{"class":3778},[3772,16537,5150],{"class":3945},[3772,16539,16540],{"class":3949},"selectWesternTrips",[3772,16542,5345],{"class":3945},[3772,16544,16545],{"class":3774,"line":4028},[3772,16546,16547],{"class":3934},"\u002F\u002F Компонент ререндериться тільки якщо результат дійсно змінився\n",[10847,16549,16551,16556],{"icon":11289,"title":16550},"Помилка: 'Cannot mutate draft outside reducer'",[3743,16552,16553,16555],{},[3829,16554,16372],{}," Спроба змінити стан поза межами reducer.",[3762,16557,16559],{"className":3925,"code":16558,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОГАНО:\nfunction MyComponent() {\n    const trips = useAppSelector((state) => state.trips.items)\n\n    const handleClick = () => {\n        trips.push(newTrip) \u002F\u002F ❌ Мутація стану напряму!\n    }\n}\n\n\u002F\u002F ✅ ДОБРЕ:\nfunction MyComponent() {\n    const dispatch = useAppDispatch()\n\n    const handleClick = () => {\n        dispatch(addTrip(newTrip)) \u002F\u002F ✅ Через дію!\n    }\n}\n",[3769,16560,16561,16566,16574,16604,16608,16621,16639,16643,16647,16651,16656,16664,16676,16680,16692,16710,16714],{"__ignoreMap":3767},[3772,16562,16563],{"class":3774,"line":3775},[3772,16564,16565],{"class":3934},"\u002F\u002F ❌ ПОГАНО:\n",[3772,16567,16568,16570,16572],{"class":3774,"line":3938},[3772,16569,5144],{"class":3980},[3772,16571,10937],{"class":3778},[3772,16573,4205],{"class":3945},[3772,16575,16576,16578,16580,16582,16584,16586,16588,16590,16592,16594,16596,16598,16600,16602],{"class":3774,"line":3961},[3772,16577,10944],{"class":3980},[3772,16579,10947],{"class":3984},[3772,16581,3988],{"class":3945},[3772,16583,10952],{"class":3778},[3772,16585,6056],{"class":3945},[3772,16587,5153],{"class":3949},[3772,16589,5765],{"class":3945},[3772,16591,5768],{"class":3980},[3772,16593,5353],{"class":3949},[3772,16595,4059],{"class":3945},[3772,16597,7557],{"class":3949},[3772,16599,4059],{"class":3945},[3772,16601,5237],{"class":3949},[3772,16603,5345],{"class":3945},[3772,16605,16606],{"class":3774,"line":3968},[3772,16607,3965],{"emptyLinePlaceholder":3964},[3772,16609,16610,16612,16615,16617,16619],{"class":3774,"line":3974},[3772,16611,10944],{"class":3980},[3772,16613,16614],{"class":3778}," handleClick",[3772,16616,14701],{"class":3945},[3772,16618,5768],{"class":3980},[3772,16620,4002],{"class":3945},[3772,16622,16623,16626,16628,16630,16632,16634,16636],{"class":3774,"line":3996},[3772,16624,16625],{"class":3949},"        trips",[3772,16627,4059],{"class":3945},[3772,16629,5337],{"class":3778},[3772,16631,5150],{"class":3945},[3772,16633,10983],{"class":3949},[3772,16635,5765],{"class":3945},[3772,16637,16638],{"class":3934},"\u002F\u002F ❌ Мутація стану напряму!\n",[3772,16640,16641],{"class":3774,"line":4005},[3772,16642,4906],{"class":3945},[3772,16644,16645],{"class":3774,"line":4011},[3772,16646,4316],{"class":3945},[3772,16648,16649],{"class":3774,"line":4017},[3772,16650,3965],{"emptyLinePlaceholder":3964},[3772,16652,16653],{"class":3774,"line":4023},[3772,16654,16655],{"class":3934},"\u002F\u002F ✅ ДОБРЕ:\n",[3772,16657,16658,16660,16662],{"class":3774,"line":4028},[3772,16659,5144],{"class":3980},[3772,16661,10937],{"class":3778},[3772,16663,4205],{"class":3945},[3772,16665,16666,16668,16670,16672,16674],{"class":3774,"line":4034},[3772,16667,10944],{"class":3980},[3772,16669,14600],{"class":3984},[3772,16671,3988],{"class":3945},[3772,16673,14537],{"class":3778},[3772,16675,13941],{"class":3945},[3772,16677,16678],{"class":3774,"line":4068},[3772,16679,3965],{"emptyLinePlaceholder":3964},[3772,16681,16682,16684,16686,16688,16690],{"class":3774,"line":4313},[3772,16683,10944],{"class":3980},[3772,16685,16614],{"class":3778},[3772,16687,14701],{"class":3945},[3772,16689,5768],{"class":3980},[3772,16691,4002],{"class":3945},[3772,16693,16694,16696,16698,16700,16702,16704,16707],{"class":3774,"line":4470},[3772,16695,14715],{"class":3778},[3772,16697,5150],{"class":3945},[3772,16699,6788],{"class":3778},[3772,16701,5150],{"class":3945},[3772,16703,10983],{"class":3949},[3772,16705,16706],{"class":3945},")) ",[3772,16708,16709],{"class":3934},"\u002F\u002F ✅ Через дію!\n",[3772,16711,16712],{"class":3774,"line":4879},[3772,16713,4906],{"class":3945},[3772,16715,16716],{"class":3774,"line":4892},[3772,16717,4316],{"class":3945},[10847,16719,16722,16727],{"icon":16720,"title":16721},"i-lucide-clock","Помилка: Асинхронна логіка в reducer",[3743,16723,16724,16726],{},[3829,16725,16372],{}," Редюсери мають бути синхронними.",[3762,16728,16730],{"className":3925,"code":16729,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОГАНО:\nreducers: {\n    async loadTrips(state) {\n        const data = await fetch('\u002Fapi\u002Ftrips')\n        state.items = data\n    }\n}\n\n\u002F\u002F ✅ ДОБРЕ: Використовуйте createAsyncThunk\nexport const loadTripsThunk = createAsyncThunk(\n    'trips\u002Fload',\n    async () => {\n        const response = await fetch('\u002Fapi\u002Ftrips')\n        return response.json()\n    }\n)\n",[3769,16731,16732,16736,16742,16756,16777,16790,16794,16798,16802,16807,16822,16829,16840,16858,16871,16875],{"__ignoreMap":3767},[3772,16733,16734],{"class":3774,"line":3775},[3772,16735,16565],{"class":3934},[3772,16737,16738,16740],{"class":3774,"line":3938},[3772,16739,8385],{"class":4719},[3772,16741,4723],{"class":3945},[3772,16743,16744,16747,16750,16752,16754],{"class":3774,"line":3961},[3772,16745,16746],{"class":3949},"    async",[3772,16748,16749],{"class":3778}," loadTrips",[3772,16751,5150],{"class":3945},[3772,16753,5153],{"class":3949},[3772,16755,5166],{"class":3945},[3772,16757,16758,16760,16763,16765,16767,16770,16772,16775],{"class":3774,"line":3968},[3772,16759,10557],{"class":3980},[3772,16761,16762],{"class":3984}," data",[3772,16764,3988],{"class":3945},[3772,16766,15166],{"class":3941},[3772,16768,16769],{"class":3778}," fetch",[3772,16771,5150],{"class":3945},[3772,16773,16774],{"class":3781},"'\u002Fapi\u002Ftrips'",[3772,16776,5345],{"class":3945},[3772,16778,16779,16781,16783,16785,16787],{"class":3774,"line":3974},[3772,16780,9935],{"class":3949},[3772,16782,4059],{"class":3945},[3772,16784,5237],{"class":3949},[3772,16786,3988],{"class":3945},[3772,16788,16789],{"class":3949},"data\n",[3772,16791,16792],{"class":3774,"line":3996},[3772,16793,4906],{"class":3945},[3772,16795,16796],{"class":3774,"line":4005},[3772,16797,4316],{"class":3945},[3772,16799,16800],{"class":3774,"line":4011},[3772,16801,3965],{"emptyLinePlaceholder":3964},[3772,16803,16804],{"class":3774,"line":4017},[3772,16805,16806],{"class":3934},"\u002F\u002F ✅ ДОБРЕ: Використовуйте createAsyncThunk\n",[3772,16808,16809,16811,16813,16816,16818,16820],{"class":3774,"line":4023},[3772,16810,3977],{"class":3941},[3772,16812,3981],{"class":3980},[3772,16814,16815],{"class":3984}," loadTripsThunk",[3772,16817,3988],{"class":3945},[3772,16819,3853],{"class":3778},[3772,16821,12904],{"class":3945},[3772,16823,16824,16827],{"class":3774,"line":4028},[3772,16825,16826],{"class":3781},"    'trips\u002Fload'",[3772,16828,4806],{"class":3945},[3772,16830,16831,16833,16836,16838],{"class":3774,"line":4034},[3772,16832,16746],{"class":3980},[3772,16834,16835],{"class":3945}," () ",[3772,16837,5768],{"class":3980},[3772,16839,4002],{"class":3945},[3772,16841,16842,16844,16846,16848,16850,16852,16854,16856],{"class":3774,"line":4068},[3772,16843,10557],{"class":3980},[3772,16845,15161],{"class":3984},[3772,16847,3988],{"class":3945},[3772,16849,15166],{"class":3941},[3772,16851,16769],{"class":3778},[3772,16853,5150],{"class":3945},[3772,16855,16774],{"class":3781},[3772,16857,5345],{"class":3945},[3772,16859,16860,16862,16864,16866,16869],{"class":3774,"line":4313},[3772,16861,5202],{"class":3941},[3772,16863,15161],{"class":3949},[3772,16865,4059],{"class":3945},[3772,16867,16868],{"class":3778},"json",[3772,16870,13941],{"class":3945},[3772,16872,16873],{"class":3774,"line":4470},[3772,16874,4906],{"class":3945},[3772,16876,16877],{"class":3774,"line":4879},[3772,16878,5345],{"class":3945},[4495,16880],{},[3747,16882,14455,16884,16886],{"id":16883},"_4-store-configurestore-та-конвеєр-middleware-продовження",[3769,16885,3850],{},") та конвеєр Middleware (продовження)",[7025,16888,16890],{"id":16889},"налаштування-middleware-та-користувацькі-перехоплювачі","Налаштування Middleware та користувацькі перехоплювачі",[3743,16892,16893],{},"Middleware — це функція вищого порядку, яка перехоплює кожну дію перед тим, як вона потрапить у редуктор:",[5417,16895,16896],{},[3762,16897,16899],{"className":5422,"code":16898,"language":5424,"meta":3767,"style":3767},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam defaultFontName \"Helvetica\"\nskinparam defaultFontSize 12\n\nactor \"UI Dispatch\" as UI #bfdbfe\nparticipant \"Custom Logger Middleware\" as M1 #fef08a\nparticipant \"Serializable Check Middleware\" as M2 #fed7aa\nparticipant \"Redux-Thunk Middleware\" as M3 #fed7aa\nparticipant \"Reducers (RootReducer)\" as Reducer #bbf7d0\ndatabase \"Store State\" as State #e2e8f0\n\nUI -> M1 : dispatch(action)\nM1 -> M1 : console.log(\"[ACTION START]\", action.type)\nM1 -> M2 : next(action)\nM2 -> M2 : Перевірка чи немає Date\u002FMap\u002FFunction\nM2 -> M3 : next(action)\nM3 -> Reducer : next(action)\nReducer -> State : Трансформація стану\nState --> UI : Сповіщення передплатників useSelector\n@enduml\n",[3769,16900,16901,16905,16909,16913,16917,16921,16925,16930,16935,16940,16945,16950,16955,16959,16964,16969,16974,16979,16984,16989,16994,16999],{"__ignoreMap":3767},[3772,16902,16903],{"class":3774,"line":3775},[3772,16904,5431],{},[3772,16906,16907],{"class":3774,"line":3938},[3772,16908,5436],{},[3772,16910,16911],{"class":3774,"line":3961},[3772,16912,5441],{},[3772,16914,16915],{"class":3774,"line":3968},[3772,16916,5446],{},[3772,16918,16919],{"class":3774,"line":3974},[3772,16920,8005],{},[3772,16922,16923],{"class":3774,"line":3996},[3772,16924,3965],{"emptyLinePlaceholder":3964},[3772,16926,16927],{"class":3774,"line":4005},[3772,16928,16929],{},"actor \"UI Dispatch\" as UI #bfdbfe\n",[3772,16931,16932],{"class":3774,"line":4011},[3772,16933,16934],{},"participant \"Custom Logger Middleware\" as M1 #fef08a\n",[3772,16936,16937],{"class":3774,"line":4017},[3772,16938,16939],{},"participant \"Serializable Check Middleware\" as M2 #fed7aa\n",[3772,16941,16942],{"class":3774,"line":4023},[3772,16943,16944],{},"participant \"Redux-Thunk Middleware\" as M3 #fed7aa\n",[3772,16946,16947],{"class":3774,"line":4028},[3772,16948,16949],{},"participant \"Reducers (RootReducer)\" as Reducer #bbf7d0\n",[3772,16951,16952],{"class":3774,"line":4034},[3772,16953,16954],{},"database \"Store State\" as State #e2e8f0\n",[3772,16956,16957],{"class":3774,"line":4068},[3772,16958,3965],{"emptyLinePlaceholder":3964},[3772,16960,16961],{"class":3774,"line":4313},[3772,16962,16963],{},"UI -> M1 : dispatch(action)\n",[3772,16965,16966],{"class":3774,"line":4470},[3772,16967,16968],{},"M1 -> M1 : console.log(\"[ACTION START]\", action.type)\n",[3772,16970,16971],{"class":3774,"line":4879},[3772,16972,16973],{},"M1 -> M2 : next(action)\n",[3772,16975,16976],{"class":3774,"line":4892},[3772,16977,16978],{},"M2 -> M2 : Перевірка чи немає Date\u002FMap\u002FFunction\n",[3772,16980,16981],{"class":3774,"line":4903},[3772,16982,16983],{},"M2 -> M3 : next(action)\n",[3772,16985,16986],{"class":3774,"line":4909},[3772,16987,16988],{},"M3 -> Reducer : next(action)\n",[3772,16990,16991],{"class":3774,"line":5521},[3772,16992,16993],{},"Reducer -> State : Трансформація стану\n",[3772,16995,16996],{"class":3774,"line":5527},[3772,16997,16998],{},"State --> UI : Сповіщення передплатників useSelector\n",[3772,17000,17001],{"class":3774,"line":5533},[3772,17002,5553],{},[3743,17004,17005,17006,4094],{},"Створимо користувацький middleware для моніторингу дій та налаштуємо ",[3769,17007,3850],{},[3762,17009,17011],{"className":3925,"code":17010,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fmiddleware\u002FanalyticsLogger.ts\nimport { Middleware } from '@reduxjs\u002Ftoolkit'\nimport type { RootState } from '..\u002Findex'\n\n\u002F**\n * Логує кожну дію та час її виконання у консоль під час розробки\n *\u002F\nexport const analyticsLoggerMiddleware: Middleware\u003C{}, RootState> = (storeApi) => (next) => (action: any) => {\n    if (__DEV__) {\n        const startTime = Date.now()\n        console.log(`%c[ACTION] ${action.type}`, 'color: #2563eb; font-weight: bold;', action.payload)\n\n        const result = next(action)\n\n        const duration = Date.now() - startTime\n        console.log(`%c[STATE AFTER] (${duration}ms)`, 'color: #059669;', storeApi.getState())\n\n        return result\n    }\n\n    return next(action)\n}\n",[3769,17012,17013,17018,17033,17049,17053,17058,17063,17068,17119,17129,17146,17187,17191,17208,17212,17233,17272,17276,17283,17287,17291,17304],{"__ignoreMap":3767},[3772,17014,17015],{"class":3774,"line":3775},[3772,17016,17017],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fmiddleware\u002FanalyticsLogger.ts\n",[3772,17019,17020,17022,17024,17027,17029,17031],{"class":3774,"line":3938},[3772,17021,3942],{"class":3941},[3772,17023,3946],{"class":3945},[3772,17025,17026],{"class":3949},"Middleware",[3772,17028,3952],{"class":3945},[3772,17030,3955],{"class":3941},[3772,17032,3958],{"class":3781},[3772,17034,17035,17037,17039,17041,17043,17045,17047],{"class":3774,"line":3961},[3772,17036,3942],{"class":3941},[3772,17038,4039],{"class":3941},[3772,17040,3946],{"class":3945},[3772,17042,14962],{"class":3949},[3772,17044,3952],{"class":3945},[3772,17046,3955],{"class":3941},[3772,17048,14969],{"class":3781},[3772,17050,17051],{"class":3774,"line":3968},[3772,17052,3965],{"emptyLinePlaceholder":3964},[3772,17054,17055],{"class":3774,"line":3974},[3772,17056,17057],{"class":3934},"\u002F**\n",[3772,17059,17060],{"class":3774,"line":3996},[3772,17061,17062],{"class":3934}," * Логує кожну дію та час її виконання у консоль під час розробки\n",[3772,17064,17065],{"class":3774,"line":4005},[3772,17066,17067],{"class":3934}," *\u002F\n",[3772,17069,17070,17072,17074,17077,17079,17081,17084,17086,17089,17092,17094,17096,17098,17101,17103,17105,17107,17109,17111,17113,17115,17117],{"class":3774,"line":4011},[3772,17071,3977],{"class":3941},[3772,17073,3981],{"class":3980},[3772,17075,17076],{"class":3778}," analyticsLoggerMiddleware",[3772,17078,4800],{"class":3945},[3772,17080,17026],{"class":4042},[3772,17082,17083],{"class":3945},"\u003C{}, ",[3772,17085,14962],{"class":4042},[3772,17087,17088],{"class":3945},"> = (",[3772,17090,17091],{"class":3949},"storeApi",[3772,17093,5765],{"class":3945},[3772,17095,5768],{"class":3980},[3772,17097,5179],{"class":3945},[3772,17099,17100],{"class":3949},"next",[3772,17102,5765],{"class":3945},[3772,17104,5768],{"class":3980},[3772,17106,5179],{"class":3945},[3772,17108,5163],{"class":3949},[3772,17110,4800],{"class":3945},[3772,17112,6955],{"class":4042},[3772,17114,5765],{"class":3945},[3772,17116,5768],{"class":3980},[3772,17118,4002],{"class":3945},[3772,17120,17121,17123,17125,17127],{"class":3774,"line":4017},[3772,17122,5176],{"class":3941},[3772,17124,5179],{"class":3945},[3772,17126,14004],{"class":3949},[3772,17128,5166],{"class":3945},[3772,17130,17131,17133,17136,17138,17140,17142,17144],{"class":3774,"line":4023},[3772,17132,10557],{"class":3980},[3772,17134,17135],{"class":3984}," startTime",[3772,17137,3988],{"class":3945},[3772,17139,13933],{"class":3949},[3772,17141,4059],{"class":3945},[3772,17143,13938],{"class":3778},[3772,17145,13941],{"class":3945},[3772,17147,17148,17150,17152,17154,17156,17159,17161,17163,17165,17167,17169,17172,17174,17177,17179,17181,17183,17185],{"class":3774,"line":4028},[3772,17149,13347],{"class":3949},[3772,17151,4059],{"class":3945},[3772,17153,7289],{"class":3778},[3772,17155,5150],{"class":3945},[3772,17157,17158],{"class":3781},"`%c[ACTION] ",[3772,17160,15182],{"class":3980},[3772,17162,5163],{"class":3949},[3772,17164,4059],{"class":4272},[3772,17166,5048],{"class":3949},[3772,17168,4235],{"class":3980},[3772,17170,17171],{"class":3781},"`",[3772,17173,3847],{"class":3945},[3772,17175,17176],{"class":3781},"'color: #2563eb; font-weight: bold;'",[3772,17178,3847],{"class":3945},[3772,17180,5163],{"class":3949},[3772,17182,4059],{"class":3945},[3772,17184,5059],{"class":3949},[3772,17186,5345],{"class":3945},[3772,17188,17189],{"class":3774,"line":4034},[3772,17190,3965],{"emptyLinePlaceholder":3964},[3772,17192,17193,17195,17198,17200,17202,17204,17206],{"class":3774,"line":4068},[3772,17194,10557],{"class":3980},[3772,17196,17197],{"class":3984}," result",[3772,17199,3988],{"class":3945},[3772,17201,17100],{"class":3778},[3772,17203,5150],{"class":3945},[3772,17205,5163],{"class":3949},[3772,17207,5345],{"class":3945},[3772,17209,17210],{"class":3774,"line":4313},[3772,17211,3965],{"emptyLinePlaceholder":3964},[3772,17213,17214,17216,17219,17221,17223,17225,17227,17230],{"class":3774,"line":4470},[3772,17215,10557],{"class":3980},[3772,17217,17218],{"class":3984}," duration",[3772,17220,3988],{"class":3945},[3772,17222,13933],{"class":3949},[3772,17224,4059],{"class":3945},[3772,17226,13938],{"class":3778},[3772,17228,17229],{"class":3945},"() - ",[3772,17231,17232],{"class":3949},"startTime\n",[3772,17234,17235,17237,17239,17241,17243,17246,17248,17251,17253,17256,17258,17261,17263,17265,17267,17269],{"class":3774,"line":4879},[3772,17236,13347],{"class":3949},[3772,17238,4059],{"class":3945},[3772,17240,7289],{"class":3778},[3772,17242,5150],{"class":3945},[3772,17244,17245],{"class":3781},"`%c[STATE AFTER] (",[3772,17247,15182],{"class":3980},[3772,17249,17250],{"class":3949},"duration",[3772,17252,4235],{"class":3980},[3772,17254,17255],{"class":3781},"ms)`",[3772,17257,3847],{"class":3945},[3772,17259,17260],{"class":3781},"'color: #059669;'",[3772,17262,3847],{"class":3945},[3772,17264,17091],{"class":3949},[3772,17266,4059],{"class":3945},[3772,17268,4062],{"class":3778},[3772,17270,17271],{"class":3945},"())\n",[3772,17273,17274],{"class":3774,"line":4892},[3772,17275,3965],{"emptyLinePlaceholder":3964},[3772,17277,17278,17280],{"class":3774,"line":4903},[3772,17279,5202],{"class":3941},[3772,17281,17282],{"class":3949}," result\n",[3772,17284,17285],{"class":3774,"line":4909},[3772,17286,4906],{"class":3945},[3772,17288,17289],{"class":3774,"line":5521},[3772,17290,3965],{"emptyLinePlaceholder":3964},[3772,17292,17293,17295,17298,17300,17302],{"class":3774,"line":5527},[3772,17294,4210],{"class":3941},[3772,17296,17297],{"class":3778}," next",[3772,17299,5150],{"class":3945},[3772,17301,5163],{"class":3949},[3772,17303,5345],{"class":3945},[3772,17305,17306],{"class":3774,"line":5533},[3772,17307,4316],{"class":3945},[3762,17309,17311],{"className":3925,"code":17310,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Findex.ts\nimport { configureStore, combineReducers } from '@reduxjs\u002Ftoolkit'\nimport tripsReducer from '.\u002Fslices\u002FtripsSlice'\nimport settingsReducer from '.\u002Fslices\u002FsettingsSlice'\nimport { analyticsLoggerMiddleware } from '.\u002Fmiddleware\u002FanalyticsLogger'\n\nconst rootReducer = combineReducers({\n    trips: tripsReducer,\n    settings: settingsReducer,\n})\n\nexport const store = configureStore({\n    reducer: rootReducer,\n    middleware: (getDefaultMiddleware) =>\n        getDefaultMiddleware({\n            \u002F\u002F Налаштування стандартних перевірок RTK\n            thunk: true,\n            immutableCheck: { warnAfter: 128 },\n            serializableCheck: {\n                ignoredActions: ['persist\u002FPERSIST'],\n            },\n        }).concat(analyticsLoggerMiddleware),\n    devTools: process.env.NODE_ENV !== 'production',\n})\n\n\u002F\u002F Експорт глобальних типів\nexport type RootState = ReturnType\u003Ctypeof store.getState>\nexport type AppDispatch = typeof store.dispatch\n",[3769,17312,17313,17317,17335,17346,17358,17374,17378,17390,17398,17407,17411,17415,17429,17437,17453,17460,17465,17474,17489,17496,17508,17512,17526,17551,17555,17559,17564,17588],{"__ignoreMap":3767},[3772,17314,17315],{"class":3774,"line":3775},[3772,17316,3935],{"class":3934},[3772,17318,17319,17321,17323,17325,17327,17329,17331,17333],{"class":3774,"line":3938},[3772,17320,3942],{"class":3941},[3772,17322,3946],{"class":3945},[3772,17324,3850],{"class":3949},[3772,17326,3847],{"class":3945},[3772,17328,6194],{"class":3949},[3772,17330,3952],{"class":3945},[3772,17332,3955],{"class":3941},[3772,17334,3958],{"class":3781},[3772,17336,17337,17339,17341,17343],{"class":3774,"line":3961},[3772,17338,3942],{"class":3941},[3772,17340,5147],{"class":3949},[3772,17342,6211],{"class":3941},[3772,17344,17345],{"class":3781}," '.\u002Fslices\u002FtripsSlice'\n",[3772,17347,17348,17350,17353,17355],{"class":3774,"line":3968},[3772,17349,3942],{"class":3941},[3772,17351,17352],{"class":3949}," settingsReducer",[3772,17354,6211],{"class":3941},[3772,17356,17357],{"class":3781}," '.\u002Fslices\u002FsettingsSlice'\n",[3772,17359,17360,17362,17364,17367,17369,17371],{"class":3774,"line":3974},[3772,17361,3942],{"class":3941},[3772,17363,3946],{"class":3945},[3772,17365,17366],{"class":3949},"analyticsLoggerMiddleware",[3772,17368,3952],{"class":3945},[3772,17370,3955],{"class":3941},[3772,17372,17373],{"class":3781}," '.\u002Fmiddleware\u002FanalyticsLogger'\n",[3772,17375,17376],{"class":3774,"line":3996},[3772,17377,3965],{"emptyLinePlaceholder":3964},[3772,17379,17380,17382,17384,17386,17388],{"class":3774,"line":4005},[3772,17381,5885],{"class":3980},[3772,17383,6257],{"class":3984},[3772,17385,3988],{"class":3945},[3772,17387,6194],{"class":3778},[3772,17389,3993],{"class":3945},[3772,17391,17392,17394,17396],{"class":3774,"line":4011},[3772,17393,6268],{"class":3949},[3772,17395,5147],{"class":3949},[3772,17397,4806],{"class":3945},[3772,17399,17400,17403,17405],{"class":3774,"line":4017},[3772,17401,17402],{"class":3949},"    settings:",[3772,17404,17352],{"class":3949},[3772,17406,4806],{"class":3945},[3772,17408,17409],{"class":3774,"line":4023},[3772,17410,4020],{"class":3945},[3772,17412,17413],{"class":3774,"line":4028},[3772,17414,3965],{"emptyLinePlaceholder":3964},[3772,17416,17417,17419,17421,17423,17425,17427],{"class":3774,"line":4034},[3772,17418,3977],{"class":3941},[3772,17420,3981],{"class":3980},[3772,17422,3985],{"class":3984},[3772,17424,3988],{"class":3945},[3772,17426,3850],{"class":3778},[3772,17428,3993],{"class":3945},[3772,17430,17431,17433,17435],{"class":3774,"line":4068},[3772,17432,3999],{"class":3949},[3772,17434,6257],{"class":3949},[3772,17436,4806],{"class":3945},[3772,17438,17439,17442,17444,17446,17449,17451],{"class":3774,"line":4313},[3772,17440,17441],{"class":3778},"    middleware",[3772,17443,4094],{"class":3949},[3772,17445,5179],{"class":3945},[3772,17447,17448],{"class":3949},"getDefaultMiddleware",[3772,17450,5765],{"class":3945},[3772,17452,11064],{"class":3980},[3772,17454,17455,17458],{"class":3774,"line":4470},[3772,17456,17457],{"class":3778},"        getDefaultMiddleware",[3772,17459,3993],{"class":3945},[3772,17461,17462],{"class":3774,"line":4879},[3772,17463,17464],{"class":3934},"            \u002F\u002F Налаштування стандартних перевірок RTK\n",[3772,17466,17467,17470,17472],{"class":3774,"line":4892},[3772,17468,17469],{"class":3949},"            thunk:",[3772,17471,6116],{"class":3980},[3772,17473,4806],{"class":3945},[3772,17475,17476,17479,17481,17484,17487],{"class":3774,"line":4903},[3772,17477,17478],{"class":3949},"            immutableCheck:",[3772,17480,3946],{"class":3945},[3772,17482,17483],{"class":3949},"warnAfter:",[3772,17485,17486],{"class":8916}," 128",[3772,17488,4761],{"class":3945},[3772,17490,17491,17494],{"class":3774,"line":4909},[3772,17492,17493],{"class":3949},"            serializableCheck:",[3772,17495,4002],{"class":3945},[3772,17497,17498,17501,17503,17506],{"class":3774,"line":5521},[3772,17499,17500],{"class":3949},"                ignoredActions:",[3772,17502,5221],{"class":3945},[3772,17504,17505],{"class":3781},"'persist\u002FPERSIST'",[3772,17507,5240],{"class":3945},[3772,17509,17510],{"class":3774,"line":5527},[3772,17511,8838],{"class":3945},[3772,17513,17514,17517,17520,17522,17524],{"class":3774,"line":5533},[3772,17515,17516],{"class":3945},"        }).",[3772,17518,17519],{"class":3778},"concat",[3772,17521,5150],{"class":3945},[3772,17523,17366],{"class":3949},[3772,17525,6082],{"class":3945},[3772,17527,17528,17531,17534,17536,17539,17541,17544,17546,17549],{"class":3774,"line":5539},[3772,17529,17530],{"class":3949},"    devTools:",[3772,17532,17533],{"class":3949}," process",[3772,17535,4059],{"class":3945},[3772,17537,17538],{"class":3949},"env",[3772,17540,4059],{"class":3945},[3772,17542,17543],{"class":3984},"NODE_ENV",[3772,17545,6073],{"class":3945},[3772,17547,17548],{"class":3781},"'production'",[3772,17550,4806],{"class":3945},[3772,17552,17553],{"class":3774,"line":5545},[3772,17554,4020],{"class":3945},[3772,17556,17557],{"class":3774,"line":5550},[3772,17558,3965],{"emptyLinePlaceholder":3964},[3772,17560,17561],{"class":3774,"line":6121},[3772,17562,17563],{"class":3934},"\u002F\u002F Експорт глобальних типів\n",[3772,17565,17566,17568,17570,17572,17574,17576,17578,17580,17582,17584,17586],{"class":3774,"line":6131},[3772,17567,3977],{"class":3941},[3772,17569,4039],{"class":3980},[3772,17571,4043],{"class":4042},[3772,17573,3988],{"class":3945},[3772,17575,4048],{"class":4042},[3772,17577,4051],{"class":3945},[3772,17579,4054],{"class":3980},[3772,17581,3985],{"class":3949},[3772,17583,4059],{"class":3945},[3772,17585,4062],{"class":3949},[3772,17587,4065],{"class":3945},[3772,17589,17590,17592,17594,17596,17598,17600,17602,17604],{"class":3774,"line":6136},[3772,17591,3977],{"class":3941},[3772,17593,4039],{"class":3980},[3772,17595,4075],{"class":4042},[3772,17597,3988],{"class":3945},[3772,17599,4054],{"class":3980},[3772,17601,3985],{"class":3949},[3772,17603,4059],{"class":3945},[3772,17605,4086],{"class":3949},[4495,17607],{},[3747,17609,17611,17612],{"id":17610},"_5-сучасні-легковагі-сайд-ефекти-createlistenermiddleware","5. Сучасні легковагі сайд-ефекти: ",[3769,17613,17614],{},"createListenerMiddleware",[3743,17616,17617,17618,17621,17622,4059],{},"Раніше для складних реактивних ланцюжків (наприклад, «при зміні теми записати значення в MMKV», «при вході користувача запустити підключення WebSocket», «скасувати пошуковий запит при швидкому введенні тексту») використовували важкі бібліотеки на кшталт ",[3769,17619,17620],{},"redux-saga"," чи ",[3769,17623,17624],{},"redux-observable",[3743,17626,17627,17628,17632],{},"У сучасному Redux Toolkit офіційним інструментом є ",[3829,17629,17630],{},[3769,17631,17614],{}," — потужний, легкий (~2.5 КБ) і повністю типізований менеджер побічних ефектів:",[3762,17634,17636],{"className":3925,"code":17635,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002FlistenerMiddleware.ts\nimport { createListenerMiddleware, isAnyOf } from '@reduxjs\u002Ftoolkit'\nimport type { RootState, AppDispatch } from '.\u002Findex'\nimport { setTheme, setLocale } from '.\u002Fslices\u002FsettingsSlice'\nimport { addTrip } from '.\u002Fslices\u002FtripsSlice'\n\nexport const listenerMiddleware = createListenerMiddleware()\n\nexport const startAppListening = listenerMiddleware.startListening.withTypes\u003CRootState, AppDispatch>()\n\n\u002F\u002F 1. Слухач для збереження налаштувань у сховище при будь-якій зміні теми чи мови\nstartAppListening({\n    matcher: isAnyOf(setTheme, setLocale),\n    effect: async (action, listenerApi) => {\n        const state = listenerApi.getState()\n        console.log('[PERSIST SYNC] Збереження налаштувань на диск:', state.settings)\n        \u002F\u002F Тут виконується асинхронний запис у MMKV \u002F AsyncStorage\n    },\n})\n\n\u002F\u002F 2. Слухач з можливістю Debounce (затримки та скасування попередньої спроби)\nstartAppListening({\n    actionCreator: addTrip,\n    effect: async (action, listenerApi) => {\n        \u002F\u002F Скасовуємо попередні незавершені ефекти цього слухача\n        listenerApi.cancelActiveListeners()\n\n        \u002F\u002F Очікуємо 500мс (Debounce)\n        await listenerApi.delay(500)\n\n        \u002F\u002F Відправляємо аналітичну подію\n        console.log('[ANALYTICS] Подія: Поїздку успішно створено', action.payload.title)\n    },\n})\n",[3769,17637,17638,17643,17661,17683,17703,17717,17721,17736,17740,17775,17779,17784,17791,17809,17834,17850,17874,17879,17883,17887,17891,17896,17902,17911,17933,17938,17950,17954,17959,17979,17983,17988,18015,18019],{"__ignoreMap":3767},[3772,17639,17640],{"class":3774,"line":3775},[3772,17641,17642],{"class":3934},"\u002F\u002F src\u002Fstore\u002FlistenerMiddleware.ts\n",[3772,17644,17645,17647,17649,17651,17653,17655,17657,17659],{"class":3774,"line":3938},[3772,17646,3942],{"class":3941},[3772,17648,3946],{"class":3945},[3772,17650,17614],{"class":3949},[3772,17652,3847],{"class":3945},[3772,17654,12501],{"class":3949},[3772,17656,3952],{"class":3945},[3772,17658,3955],{"class":3941},[3772,17660,3958],{"class":3781},[3772,17662,17663,17665,17667,17669,17671,17673,17676,17678,17680],{"class":3774,"line":3961},[3772,17664,3942],{"class":3941},[3772,17666,4039],{"class":3941},[3772,17668,3946],{"class":3945},[3772,17670,14962],{"class":3949},[3772,17672,3847],{"class":3945},[3772,17674,17675],{"class":3949},"AppDispatch",[3772,17677,3952],{"class":3945},[3772,17679,3955],{"class":3941},[3772,17681,17682],{"class":3781}," '.\u002Findex'\n",[3772,17684,17685,17687,17689,17692,17694,17697,17699,17701],{"class":3774,"line":3968},[3772,17686,3942],{"class":3941},[3772,17688,3946],{"class":3945},[3772,17690,17691],{"class":3949},"setTheme",[3772,17693,3847],{"class":3945},[3772,17695,17696],{"class":3949},"setLocale",[3772,17698,3952],{"class":3945},[3772,17700,3955],{"class":3941},[3772,17702,17357],{"class":3781},[3772,17704,17705,17707,17709,17711,17713,17715],{"class":3774,"line":3974},[3772,17706,3942],{"class":3941},[3772,17708,3946],{"class":3945},[3772,17710,6788],{"class":3949},[3772,17712,3952],{"class":3945},[3772,17714,3955],{"class":3941},[3772,17716,17345],{"class":3781},[3772,17718,17719],{"class":3774,"line":3996},[3772,17720,3965],{"emptyLinePlaceholder":3964},[3772,17722,17723,17725,17727,17730,17732,17734],{"class":3774,"line":4005},[3772,17724,3977],{"class":3941},[3772,17726,3981],{"class":3980},[3772,17728,17729],{"class":3984}," listenerMiddleware",[3772,17731,3988],{"class":3945},[3772,17733,17614],{"class":3778},[3772,17735,13941],{"class":3945},[3772,17737,17738],{"class":3774,"line":4011},[3772,17739,3965],{"emptyLinePlaceholder":3964},[3772,17741,17742,17744,17746,17749,17751,17754,17756,17759,17761,17764,17766,17768,17770,17772],{"class":3774,"line":4017},[3772,17743,3977],{"class":3941},[3772,17745,3981],{"class":3980},[3772,17747,17748],{"class":3984}," startAppListening",[3772,17750,3988],{"class":3945},[3772,17752,17753],{"class":3949},"listenerMiddleware",[3772,17755,4059],{"class":3945},[3772,17757,17758],{"class":3949},"startListening",[3772,17760,4059],{"class":3945},[3772,17762,17763],{"class":3778},"withTypes",[3772,17765,4051],{"class":3945},[3772,17767,14962],{"class":4042},[3772,17769,3847],{"class":3945},[3772,17771,17675],{"class":4042},[3772,17773,17774],{"class":3945},">()\n",[3772,17776,17777],{"class":3774,"line":4023},[3772,17778,3965],{"emptyLinePlaceholder":3964},[3772,17780,17781],{"class":3774,"line":4028},[3772,17782,17783],{"class":3934},"\u002F\u002F 1. Слухач для збереження налаштувань у сховище при будь-якій зміні теми чи мови\n",[3772,17785,17786,17789],{"class":3774,"line":4034},[3772,17787,17788],{"class":3778},"startAppListening",[3772,17790,3993],{"class":3945},[3772,17792,17793,17796,17799,17801,17803,17805,17807],{"class":3774,"line":4068},[3772,17794,17795],{"class":3949},"    matcher:",[3772,17797,17798],{"class":3778}," isAnyOf",[3772,17800,5150],{"class":3945},[3772,17802,17691],{"class":3949},[3772,17804,3847],{"class":3945},[3772,17806,17696],{"class":3949},[3772,17808,6082],{"class":3945},[3772,17810,17811,17814,17816,17819,17821,17823,17825,17828,17830,17832],{"class":3774,"line":4313},[3772,17812,17813],{"class":3778},"    effect",[3772,17815,4094],{"class":3949},[3772,17817,17818],{"class":3980}," async",[3772,17820,5179],{"class":3945},[3772,17822,5163],{"class":3949},[3772,17824,3847],{"class":3945},[3772,17826,17827],{"class":3949},"listenerApi",[3772,17829,5765],{"class":3945},[3772,17831,5768],{"class":3980},[3772,17833,4002],{"class":3945},[3772,17835,17836,17838,17840,17842,17844,17846,17848],{"class":3774,"line":4470},[3772,17837,10557],{"class":3980},[3772,17839,5353],{"class":3984},[3772,17841,3988],{"class":3945},[3772,17843,17827],{"class":3949},[3772,17845,4059],{"class":3945},[3772,17847,4062],{"class":3778},[3772,17849,13941],{"class":3945},[3772,17851,17852,17854,17856,17858,17860,17863,17865,17867,17869,17872],{"class":3774,"line":4879},[3772,17853,13347],{"class":3949},[3772,17855,4059],{"class":3945},[3772,17857,7289],{"class":3778},[3772,17859,5150],{"class":3945},[3772,17861,17862],{"class":3781},"'[PERSIST SYNC] Збереження налаштувань на диск:'",[3772,17864,3847],{"class":3945},[3772,17866,5153],{"class":3949},[3772,17868,4059],{"class":3945},[3772,17870,17871],{"class":3949},"settings",[3772,17873,5345],{"class":3945},[3772,17875,17876],{"class":3774,"line":4892},[3772,17877,17878],{"class":3934},"        \u002F\u002F Тут виконується асинхронний запис у MMKV \u002F AsyncStorage\n",[3772,17880,17881],{"class":3774,"line":4903},[3772,17882,4014],{"class":3945},[3772,17884,17885],{"class":3774,"line":4909},[3772,17886,4020],{"class":3945},[3772,17888,17889],{"class":3774,"line":5521},[3772,17890,3965],{"emptyLinePlaceholder":3964},[3772,17892,17893],{"class":3774,"line":5527},[3772,17894,17895],{"class":3934},"\u002F\u002F 2. Слухач з можливістю Debounce (затримки та скасування попередньої спроби)\n",[3772,17897,17898,17900],{"class":3774,"line":5533},[3772,17899,17788],{"class":3778},[3772,17901,3993],{"class":3945},[3772,17903,17904,17907,17909],{"class":3774,"line":5539},[3772,17905,17906],{"class":3949},"    actionCreator:",[3772,17908,5756],{"class":3949},[3772,17910,4806],{"class":3945},[3772,17912,17913,17915,17917,17919,17921,17923,17925,17927,17929,17931],{"class":3774,"line":5545},[3772,17914,17813],{"class":3778},[3772,17916,4094],{"class":3949},[3772,17918,17818],{"class":3980},[3772,17920,5179],{"class":3945},[3772,17922,5163],{"class":3949},[3772,17924,3847],{"class":3945},[3772,17926,17827],{"class":3949},[3772,17928,5765],{"class":3945},[3772,17930,5768],{"class":3980},[3772,17932,4002],{"class":3945},[3772,17934,17935],{"class":3774,"line":5550},[3772,17936,17937],{"class":3934},"        \u002F\u002F Скасовуємо попередні незавершені ефекти цього слухача\n",[3772,17939,17940,17943,17945,17948],{"class":3774,"line":6121},[3772,17941,17942],{"class":3949},"        listenerApi",[3772,17944,4059],{"class":3945},[3772,17946,17947],{"class":3778},"cancelActiveListeners",[3772,17949,13941],{"class":3945},[3772,17951,17952],{"class":3774,"line":6131},[3772,17953,3965],{"emptyLinePlaceholder":3964},[3772,17955,17956],{"class":3774,"line":6136},[3772,17957,17958],{"class":3934},"        \u002F\u002F Очікуємо 500мс (Debounce)\n",[3772,17960,17961,17964,17967,17969,17972,17974,17977],{"class":3774,"line":6142},[3772,17962,17963],{"class":3941},"        await",[3772,17965,17966],{"class":3949}," listenerApi",[3772,17968,4059],{"class":3945},[3772,17970,17971],{"class":3778},"delay",[3772,17973,5150],{"class":3945},[3772,17975,17976],{"class":8916},"500",[3772,17978,5345],{"class":3945},[3772,17980,17981],{"class":3774,"line":6150},[3772,17982,3965],{"emptyLinePlaceholder":3964},[3772,17984,17985],{"class":3774,"line":6157},[3772,17986,17987],{"class":3934},"        \u002F\u002F Відправляємо аналітичну подію\n",[3772,17989,17990,17992,17994,17996,17998,18001,18003,18005,18007,18009,18011,18013],{"class":3774,"line":6162},[3772,17991,13347],{"class":3949},[3772,17993,4059],{"class":3945},[3772,17995,7289],{"class":3778},[3772,17997,5150],{"class":3945},[3772,17999,18000],{"class":3781},"'[ANALYTICS] Подія: Поїздку успішно створено'",[3772,18002,3847],{"class":3945},[3772,18004,5163],{"class":3949},[3772,18006,4059],{"class":3945},[3772,18008,5059],{"class":3949},[3772,18010,4059],{"class":3945},[3772,18012,7131],{"class":3949},[3772,18014,5345],{"class":3945},[3772,18016,18017],{"class":3774,"line":6629},[3772,18018,4014],{"class":3945},[3772,18020,18021],{"class":3774,"line":6653},[3772,18022,4020],{"class":3945},[3743,18024,18025],{},"Підключення listener middleware до store:",[3762,18027,18029],{"className":3925,"code":18028,"language":3927,"meta":3767,"style":3767},"export const store = configureStore({\n    reducer: rootReducer,\n    middleware: (getDefaultMiddleware) => getDefaultMiddleware().prepend(listenerMiddleware.middleware),\n})\n",[3769,18030,18031,18045,18053,18086],{"__ignoreMap":3767},[3772,18032,18033,18035,18037,18039,18041,18043],{"class":3774,"line":3775},[3772,18034,3977],{"class":3941},[3772,18036,3981],{"class":3980},[3772,18038,3985],{"class":3984},[3772,18040,3988],{"class":3945},[3772,18042,3850],{"class":3778},[3772,18044,3993],{"class":3945},[3772,18046,18047,18049,18051],{"class":3774,"line":3938},[3772,18048,3999],{"class":3949},[3772,18050,6257],{"class":3949},[3772,18052,4806],{"class":3945},[3772,18054,18055,18057,18059,18061,18063,18065,18067,18070,18072,18075,18077,18079,18081,18084],{"class":3774,"line":3961},[3772,18056,17441],{"class":3778},[3772,18058,4094],{"class":3949},[3772,18060,5179],{"class":3945},[3772,18062,17448],{"class":3949},[3772,18064,5765],{"class":3945},[3772,18066,5768],{"class":3980},[3772,18068,18069],{"class":3778}," getDefaultMiddleware",[3772,18071,7205],{"class":3945},[3772,18073,18074],{"class":3778},"prepend",[3772,18076,5150],{"class":3945},[3772,18078,17753],{"class":3949},[3772,18080,4059],{"class":3945},[3772,18082,18083],{"class":3949},"middleware",[3772,18085,6082],{"class":3945},[3772,18087,18088],{"class":3774,"line":3968},[3772,18089,4020],{"class":3945},[4495,18091],{},[3747,18093,18095,18096,18098],{"id":18094},"_6-селектори-та-мемоїзація-за-допомогою-createselector-reselect","6. Селектори та мемоїзація за допомогою ",[3769,18097,16461],{}," (Reselect)",[3743,18100,18101,18104,18105,18107],{},[3829,18102,18103],{},"Селектор"," — це чиста функція, що приймає глобальний об'єкт ",[3769,18106,14962],{}," і повертає необхідний фрагмент даних або обчислює похідні значення.",[7025,18109,18111],{"id":18110},"проблема-відсутності-мемоїзації","Проблема відсутності мемоїзації",[3743,18113,18114],{},"Розглянемо неефективний селектор:",[3762,18116,18118],{"className":3925,"code":18117,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ АНТИПАТЕРН: Постійне створення нового масиву в пам'яті!\nconst selectFilteredTrips = (state: RootState) => {\n    return state.trips.list.filter((t) => t.isFavorite) \u002F\u002F filter() повертає [] з новим посиланням!\n}\n\nfunction FavoriteTripsList() {\n    \u002F\u002F Цей компонент буде ререндеритися при БУДЬ-ЯКІЙ зміні стану в store (навіть при зміні теми!),\n    \u002F\u002F оскільки посилання на результат selectFilteredTrips ЗАВЖДИ нове!\n    const favorites = useAppSelector(selectFilteredTrips)\n    \u002F\u002F ...\n}\n",[3769,18119,18120,18125,18146,18184,18188,18192,18201,18206,18211,18229,18234],{"__ignoreMap":3767},[3772,18121,18122],{"class":3774,"line":3775},[3772,18123,18124],{"class":3934},"\u002F\u002F ❌ АНТИПАТЕРН: Постійне створення нового масиву в пам'яті!\n",[3772,18126,18127,18129,18132,18134,18136,18138,18140,18142,18144],{"class":3774,"line":3938},[3772,18128,5885],{"class":3980},[3772,18130,18131],{"class":3778}," selectFilteredTrips",[3772,18133,5759],{"class":3945},[3772,18135,5153],{"class":3949},[3772,18137,4800],{"class":3945},[3772,18139,14962],{"class":4042},[3772,18141,5765],{"class":3945},[3772,18143,5768],{"class":3980},[3772,18145,4002],{"class":3945},[3772,18147,18148,18150,18152,18154,18156,18158,18160,18162,18164,18166,18168,18170,18172,18174,18176,18179,18181],{"class":3774,"line":3961},[3772,18149,4210],{"class":3941},[3772,18151,5353],{"class":3949},[3772,18153,4059],{"class":3945},[3772,18155,7557],{"class":3949},[3772,18157,4059],{"class":3945},[3772,18159,11663],{"class":3949},[3772,18161,4059],{"class":3945},[3772,18163,6053],{"class":3778},[3772,18165,6056],{"class":3945},[3772,18167,6059],{"class":3949},[3772,18169,5765],{"class":3945},[3772,18171,5768],{"class":3980},[3772,18173,6066],{"class":3949},[3772,18175,4059],{"class":3945},[3772,18177,18178],{"class":3949},"isFavorite",[3772,18180,5765],{"class":3945},[3772,18182,18183],{"class":3934},"\u002F\u002F filter() повертає [] з новим посиланням!\n",[3772,18185,18186],{"class":3774,"line":3968},[3772,18187,4316],{"class":3945},[3772,18189,18190],{"class":3774,"line":3974},[3772,18191,3965],{"emptyLinePlaceholder":3964},[3772,18193,18194,18196,18199],{"class":3774,"line":3996},[3772,18195,5144],{"class":3980},[3772,18197,18198],{"class":3778}," FavoriteTripsList",[3772,18200,4205],{"class":3945},[3772,18202,18203],{"class":3774,"line":4005},[3772,18204,18205],{"class":3934},"    \u002F\u002F Цей компонент буде ререндеритися при БУДЬ-ЯКІЙ зміні стану в store (навіть при зміні теми!),\n",[3772,18207,18208],{"class":3774,"line":4011},[3772,18209,18210],{"class":3934},"    \u002F\u002F оскільки посилання на результат selectFilteredTrips ЗАВЖДИ нове!\n",[3772,18212,18213,18215,18218,18220,18222,18224,18227],{"class":3774,"line":4017},[3772,18214,10944],{"class":3980},[3772,18216,18217],{"class":3984}," favorites",[3772,18219,3988],{"class":3945},[3772,18221,10952],{"class":3778},[3772,18223,5150],{"class":3945},[3772,18225,18226],{"class":3949},"selectFilteredTrips",[3772,18228,5345],{"class":3945},[3772,18230,18231],{"class":3774,"line":4023},[3772,18232,18233],{"class":3934},"    \u002F\u002F ...\n",[3772,18235,18236],{"class":3774,"line":4028},[3772,18237,4316],{"class":3945},[7025,18239,18241,18242],{"id":18240},"вирішення-мемоїзований-селектор-createselector","Вирішення: Мемоїзований селектор ",[3769,18243,16461],{},[3743,18245,18246,18248,18249,18252],{},[3769,18247,16461],{}," запам'ятовує (",[4508,18250,18251],{},"кешує",") останній результат обчислення. Якщо посилання на вхідні аргументи не змінилися, він миттєво повертає збережений результат без виконання важких обчислень:",[3762,18254,18256],{"className":3925,"code":18255,"language":3927,"meta":3767,"style":3767},"import { createSelector } from '@reduxjs\u002Ftoolkit'\nimport type { RootState } from '..\u002Findex'\n\n\u002F\u002F 1. Вхідні базові селектори\nconst selectTripsList = (state: RootState) => state.trips.list\nconst selectSearchQuery = (state: RootState) => state.filters.searchQuery\nconst selectSelectedRegion = (state: RootState) => state.filters.region\n\n\u002F\u002F 2. Складений мемоїзований селектор\nexport const selectFilteredTrips = createSelector(\n    [selectTripsList, selectSearchQuery, selectSelectedRegion],\n    (trips, query, region) => {\n        console.log('Виконання важкої фільтрації списку...')\n        return trips.filter((trip) => {\n            const matchesQuery = trip.title.toLowerCase().includes(query.toLowerCase())\n            const matchesRegion = region === 'all' || trip.region === region\n            return matchesQuery && matchesRegion\n        })\n    },\n)\n",[3769,18257,18258,18272,18288,18292,18297,18327,18357,18387,18391,18396,18410,18430,18451,18466,18486,18521,18550,18562,18566,18570],{"__ignoreMap":3767},[3772,18259,18260,18262,18264,18266,18268,18270],{"class":3774,"line":3775},[3772,18261,3942],{"class":3941},[3772,18263,3946],{"class":3945},[3772,18265,16461],{"class":3949},[3772,18267,3952],{"class":3945},[3772,18269,3955],{"class":3941},[3772,18271,3958],{"class":3781},[3772,18273,18274,18276,18278,18280,18282,18284,18286],{"class":3774,"line":3938},[3772,18275,3942],{"class":3941},[3772,18277,4039],{"class":3941},[3772,18279,3946],{"class":3945},[3772,18281,14962],{"class":3949},[3772,18283,3952],{"class":3945},[3772,18285,3955],{"class":3941},[3772,18287,14969],{"class":3781},[3772,18289,18290],{"class":3774,"line":3961},[3772,18291,3965],{"emptyLinePlaceholder":3964},[3772,18293,18294],{"class":3774,"line":3968},[3772,18295,18296],{"class":3934},"\u002F\u002F 1. Вхідні базові селектори\n",[3772,18298,18299,18301,18304,18306,18308,18310,18312,18314,18316,18318,18320,18322,18324],{"class":3774,"line":3974},[3772,18300,5885],{"class":3980},[3772,18302,18303],{"class":3778}," selectTripsList",[3772,18305,5759],{"class":3945},[3772,18307,5153],{"class":3949},[3772,18309,4800],{"class":3945},[3772,18311,14962],{"class":4042},[3772,18313,5765],{"class":3945},[3772,18315,5768],{"class":3980},[3772,18317,5353],{"class":3949},[3772,18319,4059],{"class":3945},[3772,18321,7557],{"class":3949},[3772,18323,4059],{"class":3945},[3772,18325,18326],{"class":3949},"list\n",[3772,18328,18329,18331,18334,18336,18338,18340,18342,18344,18346,18348,18350,18352,18354],{"class":3774,"line":3996},[3772,18330,5885],{"class":3980},[3772,18332,18333],{"class":3778}," selectSearchQuery",[3772,18335,5759],{"class":3945},[3772,18337,5153],{"class":3949},[3772,18339,4800],{"class":3945},[3772,18341,14962],{"class":4042},[3772,18343,5765],{"class":3945},[3772,18345,5768],{"class":3980},[3772,18347,5353],{"class":3949},[3772,18349,4059],{"class":3945},[3772,18351,10790],{"class":3949},[3772,18353,4059],{"class":3945},[3772,18355,18356],{"class":3949},"searchQuery\n",[3772,18358,18359,18361,18364,18366,18368,18370,18372,18374,18376,18378,18380,18382,18384],{"class":3774,"line":4005},[3772,18360,5885],{"class":3980},[3772,18362,18363],{"class":3778}," selectSelectedRegion",[3772,18365,5759],{"class":3945},[3772,18367,5153],{"class":3949},[3772,18369,4800],{"class":3945},[3772,18371,14962],{"class":4042},[3772,18373,5765],{"class":3945},[3772,18375,5768],{"class":3980},[3772,18377,5353],{"class":3949},[3772,18379,4059],{"class":3945},[3772,18381,10790],{"class":3949},[3772,18383,4059],{"class":3945},[3772,18385,18386],{"class":3949},"region\n",[3772,18388,18389],{"class":3774,"line":4011},[3772,18390,3965],{"emptyLinePlaceholder":3964},[3772,18392,18393],{"class":3774,"line":4017},[3772,18394,18395],{"class":3934},"\u002F\u002F 2. Складений мемоїзований селектор\n",[3772,18397,18398,18400,18402,18404,18406,18408],{"class":3774,"line":4023},[3772,18399,3977],{"class":3941},[3772,18401,3981],{"class":3980},[3772,18403,18131],{"class":3984},[3772,18405,3988],{"class":3945},[3772,18407,16461],{"class":3778},[3772,18409,12904],{"class":3945},[3772,18411,18412,18415,18418,18420,18423,18425,18428],{"class":3774,"line":4028},[3772,18413,18414],{"class":3945},"    [",[3772,18416,18417],{"class":3949},"selectTripsList",[3772,18419,3847],{"class":3945},[3772,18421,18422],{"class":3949},"selectSearchQuery",[3772,18424,3847],{"class":3945},[3772,18426,18427],{"class":3949},"selectSelectedRegion",[3772,18429,5240],{"class":3945},[3772,18431,18432,18434,18436,18438,18441,18443,18445,18447,18449],{"class":3774,"line":4034},[3772,18433,13565],{"class":3945},[3772,18435,7557],{"class":3949},[3772,18437,3847],{"class":3945},[3772,18439,18440],{"class":3949},"query",[3772,18442,3847],{"class":3945},[3772,18444,7140],{"class":3949},[3772,18446,5765],{"class":3945},[3772,18448,5768],{"class":3980},[3772,18450,4002],{"class":3945},[3772,18452,18453,18455,18457,18459,18461,18464],{"class":3774,"line":4068},[3772,18454,13347],{"class":3949},[3772,18456,4059],{"class":3945},[3772,18458,7289],{"class":3778},[3772,18460,5150],{"class":3945},[3772,18462,18463],{"class":3781},"'Виконання важкої фільтрації списку...'",[3772,18465,5345],{"class":3945},[3772,18467,18468,18470,18472,18474,18476,18478,18480,18482,18484],{"class":3774,"line":4313},[3772,18469,5202],{"class":3941},[3772,18471,10947],{"class":3949},[3772,18473,4059],{"class":3945},[3772,18475,6053],{"class":3778},[3772,18477,6056],{"class":3945},[3772,18479,5762],{"class":3949},[3772,18481,5765],{"class":3945},[3772,18483,5768],{"class":3980},[3772,18485,4002],{"class":3945},[3772,18487,18488,18490,18493,18495,18497,18499,18501,18503,18506,18508,18511,18513,18515,18517,18519],{"class":3774,"line":4470},[3772,18489,8995],{"class":3980},[3772,18491,18492],{"class":3984}," matchesQuery",[3772,18494,3988],{"class":3945},[3772,18496,5762],{"class":3949},[3772,18498,4059],{"class":3945},[3772,18500,7131],{"class":3949},[3772,18502,4059],{"class":3945},[3772,18504,18505],{"class":3778},"toLowerCase",[3772,18507,7205],{"class":3945},[3772,18509,18510],{"class":3778},"includes",[3772,18512,5150],{"class":3945},[3772,18514,18440],{"class":3949},[3772,18516,4059],{"class":3945},[3772,18518,18505],{"class":3778},[3772,18520,17271],{"class":3945},[3772,18522,18523,18525,18528,18530,18532,18534,18537,18540,18542,18544,18546,18548],{"class":3774,"line":4879},[3772,18524,8995],{"class":3980},[3772,18526,18527],{"class":3984}," matchesRegion",[3772,18529,3988],{"class":3945},[3772,18531,7140],{"class":3949},[3772,18533,5188],{"class":3945},[3772,18535,18536],{"class":3781},"'all'",[3772,18538,18539],{"class":3945}," || ",[3772,18541,5762],{"class":3949},[3772,18543,4059],{"class":3945},[3772,18545,7140],{"class":3949},[3772,18547,5188],{"class":3945},[3772,18549,18386],{"class":3949},[3772,18551,18552,18554,18556,18559],{"class":3774,"line":4892},[3772,18553,5977],{"class":3941},[3772,18555,18492],{"class":3949},[3772,18557,18558],{"class":3945}," && ",[3772,18560,18561],{"class":3949},"matchesRegion\n",[3772,18563,18564],{"class":3774,"line":4903},[3772,18565,14303],{"class":3945},[3772,18567,18568],{"class":3774,"line":4909},[3772,18569,4014],{"class":3945},[3772,18571,18572],{"class":3774,"line":5521},[3772,18573,5345],{"class":3945},[7025,18575,18577],{"id":18576},"пастка-параметризованих-селекторів-та-selector-factories","Пастка параметризованих селекторів та Selector Factories",[3743,18579,18580,18581,18583,18584,18587,18588,18590],{},"Коли селектор приймає динамічний аргумент (наприклад, ",[3769,18582,7598],{},"), використання одного селектора у кількох компонентах списку призводить до ",[3829,18585,18586],{},"постійного скидання кешу"," (оскільки кеш ",[3769,18589,16461],{}," за замовчуванням має розмір 1):",[3762,18592,18594],{"className":3925,"code":18593,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ НЕПРАВИЛЬНО ДЛЯ БАГАТЬОХ ЕКЗЕМПЛЯРІВ:\nexport const selectTripById = (tripId: string) =>\n    createSelector([selectTripsList], (trips) => trips.find((t) => t.id === tripId))\n\n\u002F\u002F Якщо ComponentA викликає selectTripById('1') і ComponentB викликає selectTripById('2'),\n\u002F\u002F кеш розміром 1 буде перезаписуватися при кожному виклику!\n",[3769,18595,18596,18601,18622,18666,18670,18675],{"__ignoreMap":3767},[3772,18597,18598],{"class":3774,"line":3775},[3772,18599,18600],{"class":3934},"\u002F\u002F ❌ НЕПРАВИЛЬНО ДЛЯ БАГАТЬОХ ЕКЗЕМПЛЯРІВ:\n",[3772,18602,18603,18605,18607,18610,18612,18614,18616,18618,18620],{"class":3774,"line":3938},[3772,18604,3977],{"class":3941},[3772,18606,3981],{"class":3980},[3772,18608,18609],{"class":3778}," selectTripById",[3772,18611,5759],{"class":3945},[3772,18613,7598],{"class":3949},[3772,18615,4800],{"class":3945},[3772,18617,6459],{"class":4042},[3772,18619,5765],{"class":3945},[3772,18621,11064],{"class":3980},[3772,18623,18624,18627,18630,18632,18634,18636,18638,18640,18642,18644,18646,18648,18650,18652,18654,18656,18658,18660,18662,18664],{"class":3774,"line":3961},[3772,18625,18626],{"class":3778},"    createSelector",[3772,18628,18629],{"class":3945},"([",[3772,18631,18417],{"class":3949},[3772,18633,16483],{"class":3945},[3772,18635,7557],{"class":3949},[3772,18637,5765],{"class":3945},[3772,18639,5768],{"class":3980},[3772,18641,10947],{"class":3949},[3772,18643,4059],{"class":3945},[3772,18645,7856],{"class":3778},[3772,18647,6056],{"class":3945},[3772,18649,6059],{"class":3949},[3772,18651,5765],{"class":3945},[3772,18653,5768],{"class":3980},[3772,18655,6066],{"class":3949},[3772,18657,4059],{"class":3945},[3772,18659,5812],{"class":3949},[3772,18661,5188],{"class":3945},[3772,18663,7598],{"class":3949},[3772,18665,10331],{"class":3945},[3772,18667,18668],{"class":3774,"line":3968},[3772,18669,3965],{"emptyLinePlaceholder":3964},[3772,18671,18672],{"class":3774,"line":3974},[3772,18673,18674],{"class":3934},"\u002F\u002F Якщо ComponentA викликає selectTripById('1') і ComponentB викликає selectTripById('2'),\n",[3772,18676,18677],{"class":3774,"line":3996},[3772,18678,18679],{"class":3934},"\u002F\u002F кеш розміром 1 буде перезаписуватися при кожному виклику!\n",[3743,18681,18682],{},[3829,18683,18684],{},"Архітектурно правильне рішення — Фабрика селекторів (Selector Factory):",[3762,18686,18688],{"className":3925,"code":18687,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ✅ ПРАВИЛЬНО: Створення персонального екземпляра селектора для кожного компонента\nexport const makeSelectTripById = () =>\n    createSelector([selectTripsList, (_state: RootState, tripId: string) => tripId], (trips, tripId) =>\n        trips.find((t) => t.id === tripId),\n    )\n\n\u002F\u002F Використання в компоненті картки:\nfunction TripCard({ tripId }: { tripId: string }) {\n    \u002F\u002F Створюємо персональний мемоїзований селектор один раз при монтуванні\n    const selectTrip = useMemo(makeSelectTripById, [])\n    const trip = useAppSelector((state) => selectTrip(state, tripId))\n\n    return \u003CText>{trip?.title}\u003C\u002FText>\n}\n",[3769,18689,18690,18695,18708,18752,18780,18784,18788,18793,18813,18818,18838,18868,18872,18892],{"__ignoreMap":3767},[3772,18691,18692],{"class":3774,"line":3775},[3772,18693,18694],{"class":3934},"\u002F\u002F ✅ ПРАВИЛЬНО: Створення персонального екземпляра селектора для кожного компонента\n",[3772,18696,18697,18699,18701,18704,18706],{"class":3774,"line":3938},[3772,18698,3977],{"class":3941},[3772,18700,3981],{"class":3980},[3772,18702,18703],{"class":3778}," makeSelectTripById",[3772,18705,14701],{"class":3945},[3772,18707,11064],{"class":3980},[3772,18709,18710,18712,18714,18716,18718,18721,18723,18725,18727,18729,18731,18733,18735,18737,18740,18742,18744,18746,18748,18750],{"class":3774,"line":3961},[3772,18711,18626],{"class":3778},[3772,18713,18629],{"class":3945},[3772,18715,18417],{"class":3949},[3772,18717,7128],{"class":3945},[3772,18719,18720],{"class":3949},"_state",[3772,18722,4800],{"class":3945},[3772,18724,14962],{"class":4042},[3772,18726,3847],{"class":3945},[3772,18728,7598],{"class":3949},[3772,18730,4800],{"class":3945},[3772,18732,6459],{"class":4042},[3772,18734,5765],{"class":3945},[3772,18736,5768],{"class":3980},[3772,18738,18739],{"class":3949}," tripId",[3772,18741,16483],{"class":3945},[3772,18743,7557],{"class":3949},[3772,18745,3847],{"class":3945},[3772,18747,7598],{"class":3949},[3772,18749,5765],{"class":3945},[3772,18751,11064],{"class":3980},[3772,18753,18754,18756,18758,18760,18762,18764,18766,18768,18770,18772,18774,18776,18778],{"class":3774,"line":3968},[3772,18755,16625],{"class":3949},[3772,18757,4059],{"class":3945},[3772,18759,7856],{"class":3778},[3772,18761,6056],{"class":3945},[3772,18763,6059],{"class":3949},[3772,18765,5765],{"class":3945},[3772,18767,5768],{"class":3980},[3772,18769,6066],{"class":3949},[3772,18771,4059],{"class":3945},[3772,18773,5812],{"class":3949},[3772,18775,5188],{"class":3945},[3772,18777,7598],{"class":3949},[3772,18779,6082],{"class":3945},[3772,18781,18782],{"class":3774,"line":3974},[3772,18783,4310],{"class":3945},[3772,18785,18786],{"class":3774,"line":3996},[3772,18787,3965],{"emptyLinePlaceholder":3964},[3772,18789,18790],{"class":3774,"line":4005},[3772,18791,18792],{"class":3934},"\u002F\u002F Використання в компоненті картки:\n",[3772,18794,18795,18797,18799,18801,18803,18805,18807,18809,18811],{"class":3774,"line":4011},[3772,18796,5144],{"class":3980},[3772,18798,14577],{"class":3778},[3772,18800,10074],{"class":3945},[3772,18802,7598],{"class":3949},[3772,18804,14584],{"class":3945},[3772,18806,7598],{"class":3949},[3772,18808,4800],{"class":3945},[3772,18810,6459],{"class":4042},[3772,18812,14593],{"class":3945},[3772,18814,18815],{"class":3774,"line":4017},[3772,18816,18817],{"class":3934},"    \u002F\u002F Створюємо персональний мемоїзований селектор один раз при монтуванні\n",[3772,18819,18820,18822,18825,18827,18830,18832,18835],{"class":3774,"line":4023},[3772,18821,10944],{"class":3980},[3772,18823,18824],{"class":3984}," selectTrip",[3772,18826,3988],{"class":3945},[3772,18828,18829],{"class":3778},"useMemo",[3772,18831,5150],{"class":3945},[3772,18833,18834],{"class":3949},"makeSelectTripById",[3772,18836,18837],{"class":3945},", [])\n",[3772,18839,18840,18842,18844,18846,18848,18850,18852,18854,18856,18858,18860,18862,18864,18866],{"class":3774,"line":4028},[3772,18841,10944],{"class":3980},[3772,18843,5788],{"class":3984},[3772,18845,3988],{"class":3945},[3772,18847,10952],{"class":3778},[3772,18849,6056],{"class":3945},[3772,18851,5153],{"class":3949},[3772,18853,5765],{"class":3945},[3772,18855,5768],{"class":3980},[3772,18857,18824],{"class":3778},[3772,18859,5150],{"class":3945},[3772,18861,5153],{"class":3949},[3772,18863,3847],{"class":3945},[3772,18865,7598],{"class":3949},[3772,18867,10331],{"class":3945},[3772,18869,18870],{"class":3774,"line":4034},[3772,18871,3965],{"emptyLinePlaceholder":3964},[3772,18873,18874,18876,18878,18880,18883,18885,18888,18890],{"class":3774,"line":4068},[3772,18875,4210],{"class":3941},[3772,18877,16094],{"class":3945},[3772,18879,14521],{"class":4042},[3772,18881,18882],{"class":3945},">{trip?.",[3772,18884,7131],{"class":3949},[3772,18886,18887],{"class":3945},"}\u003C\u002F",[3772,18889,14521],{"class":3949},[3772,18891,4065],{"class":3945},[3772,18893,18894],{"class":3774,"line":4313},[3772,18895,4316],{"class":3945},[4495,18897],{},[3747,18899,18901,18902,3869,18904],{"id":18900},"_7-типізовані-хуки-useappdispatch-та-useappselector","7. Типізовані хуки: ",[3769,18903,14537],{},[3769,18905,10952],{},[3743,18907,18908,18909,3869,18911,18913,18914,18916],{},"Стандартні хуки ",[3769,18910,3872],{},[3769,18912,3868],{}," з бібліотеки ",[3769,18915,3861],{}," не знають про структуру вашого застосунку. Тому створюються строго типізовані аліаси:",[3762,18918,18920],{"className":3925,"code":18919,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fhooks.ts\nimport { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux'\nimport type { RootState, AppDispatch } from '.\u002Findex'\n\n\u002F\u002F Типізований dispatch знає про всі AsyncThunkActions\nexport const useAppDispatch = () => useDispatch\u003CAppDispatch>()\n\n\u002F\u002F Типізований selector надає повне автодоповнення полів RootState\nexport const useAppSelector: TypedUseSelectorHook\u003CRootState> = useSelector\n",[3769,18921,18922,18927,18950,18970,18974,18979,19001,19005,19010],{"__ignoreMap":3767},[3772,18923,18924],{"class":3774,"line":3775},[3772,18925,18926],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fhooks.ts\n",[3772,18928,18929,18931,18933,18935,18937,18939,18941,18944,18946,18948],{"class":3774,"line":3938},[3772,18930,3942],{"class":3941},[3772,18932,3946],{"class":3945},[3772,18934,3872],{"class":3949},[3772,18936,3847],{"class":3945},[3772,18938,3868],{"class":3949},[3772,18940,3847],{"class":3945},[3772,18942,18943],{"class":3949},"TypedUseSelectorHook",[3772,18945,3952],{"class":3945},[3772,18947,3955],{"class":3941},[3772,18949,4153],{"class":3781},[3772,18951,18952,18954,18956,18958,18960,18962,18964,18966,18968],{"class":3774,"line":3961},[3772,18953,3942],{"class":3941},[3772,18955,4039],{"class":3941},[3772,18957,3946],{"class":3945},[3772,18959,14962],{"class":3949},[3772,18961,3847],{"class":3945},[3772,18963,17675],{"class":3949},[3772,18965,3952],{"class":3945},[3772,18967,3955],{"class":3941},[3772,18969,17682],{"class":3781},[3772,18971,18972],{"class":3774,"line":3968},[3772,18973,3965],{"emptyLinePlaceholder":3964},[3772,18975,18976],{"class":3774,"line":3974},[3772,18977,18978],{"class":3934},"\u002F\u002F Типізований dispatch знає про всі AsyncThunkActions\n",[3772,18980,18981,18983,18985,18988,18990,18992,18995,18997,18999],{"class":3774,"line":3996},[3772,18982,3977],{"class":3941},[3772,18984,3981],{"class":3980},[3772,18986,18987],{"class":3778}," useAppDispatch",[3772,18989,14701],{"class":3945},[3772,18991,5768],{"class":3980},[3772,18993,18994],{"class":3778}," useDispatch",[3772,18996,4051],{"class":3945},[3772,18998,17675],{"class":4042},[3772,19000,17774],{"class":3945},[3772,19002,19003],{"class":3774,"line":4005},[3772,19004,3965],{"emptyLinePlaceholder":3964},[3772,19006,19007],{"class":3774,"line":4011},[3772,19008,19009],{"class":3934},"\u002F\u002F Типізований selector надає повне автодоповнення полів RootState\n",[3772,19011,19012,19014,19016,19019,19021,19023,19025,19027,19030],{"class":3774,"line":4017},[3772,19013,3977],{"class":3941},[3772,19015,3981],{"class":3980},[3772,19017,19018],{"class":3984}," useAppSelector",[3772,19020,4800],{"class":3945},[3772,19022,18943],{"class":4042},[3772,19024,4051],{"class":3945},[3772,19026,14962],{"class":4042},[3772,19028,19029],{"class":3945},"> = ",[3772,19031,19032],{"class":3949},"useSelector\n",[7025,19034,19036,19037],{"id":19035},"оптимізація-вибірки-кількох-полів-через-shallowequal","Оптимізація вибірки кількох полів через ",[3769,19038,19039],{},"shallowEqual",[3743,19041,19042,19043,19045],{},"Якщо селектор повертає новий об'єкт із кількома полями, використовуйте функцію ",[3769,19044,19039],{},", щоб уникнути ререндеру при незмінних значеннях:",[3762,19047,19049],{"className":4129,"code":19048,"language":4131,"meta":3767,"style":3767},"import { shallowEqual } from 'react-redux'\nimport { useAppSelector } from '@\u002Fstore\u002Fhooks'\n\nfunction HeaderProfile() {\n    \u002F\u002F Ререндер відбудеться лише якщо зміниться name АБО avatar (поверхова перевірка властивостей)\n    const { name, avatar } = useAppSelector(\n        (state) => ({\n            name: state.user.profile?.name,\n            avatar: state.user.profile?.avatarUrl,\n        }),\n        shallowEqual,\n    )\n\n    return (\n        \u003CView>\n            \u003CText>{name}\u003C\u002FText>\n        \u003C\u002FView>\n    )\n}\n",[3769,19050,19051,19065,19079,19083,19092,19097,19116,19129,19151,19173,19178,19185,19189,19193,19199,19208,19228,19236,19240],{"__ignoreMap":3767},[3772,19052,19053,19055,19057,19059,19061,19063],{"class":3774,"line":3775},[3772,19054,3942],{"class":3941},[3772,19056,3946],{"class":3945},[3772,19058,19039],{"class":3949},[3772,19060,3952],{"class":3945},[3772,19062,3955],{"class":3941},[3772,19064,4153],{"class":3781},[3772,19066,19067,19069,19071,19073,19075,19077],{"class":3774,"line":3938},[3772,19068,3942],{"class":3941},[3772,19070,3946],{"class":3945},[3772,19072,10952],{"class":3949},[3772,19074,3952],{"class":3945},[3772,19076,3955],{"class":3941},[3772,19078,14548],{"class":3781},[3772,19080,19081],{"class":3774,"line":3961},[3772,19082,3965],{"emptyLinePlaceholder":3964},[3772,19084,19085,19087,19090],{"class":3774,"line":3968},[3772,19086,5144],{"class":3980},[3772,19088,19089],{"class":3778}," HeaderProfile",[3772,19091,4205],{"class":3945},[3772,19093,19094],{"class":3774,"line":3974},[3772,19095,19096],{"class":3934},"    \u002F\u002F Ререндер відбудеться лише якщо зміниться name АБО avatar (поверхова перевірка властивостей)\n",[3772,19098,19099,19101,19103,19105,19107,19110,19112,19114],{"class":3774,"line":3996},[3772,19100,10944],{"class":3980},[3772,19102,3946],{"class":3945},[3772,19104,4838],{"class":3984},[3772,19106,3847],{"class":3945},[3772,19108,19109],{"class":3984},"avatar",[3772,19111,6801],{"class":3945},[3772,19113,10952],{"class":3778},[3772,19115,12904],{"class":3945},[3772,19117,19118,19121,19123,19125,19127],{"class":3774,"line":4005},[3772,19119,19120],{"class":3945},"        (",[3772,19122,5153],{"class":3949},[3772,19124,5765],{"class":3945},[3772,19126,5768],{"class":3980},[3772,19128,5771],{"class":3945},[3772,19130,19131,19134,19136,19138,19141,19143,19145,19147,19149],{"class":3774,"line":4011},[3772,19132,19133],{"class":3949},"            name:",[3772,19135,5353],{"class":3949},[3772,19137,4059],{"class":3945},[3772,19139,19140],{"class":3949},"user",[3772,19142,4059],{"class":3945},[3772,19144,14120],{"class":3949},[3772,19146,7898],{"class":3945},[3772,19148,4838],{"class":3949},[3772,19150,4806],{"class":3945},[3772,19152,19153,19156,19158,19160,19162,19164,19166,19168,19171],{"class":3774,"line":4017},[3772,19154,19155],{"class":3949},"            avatar:",[3772,19157,5353],{"class":3949},[3772,19159,4059],{"class":3945},[3772,19161,19140],{"class":3949},[3772,19163,4059],{"class":3945},[3772,19165,14120],{"class":3949},[3772,19167,7898],{"class":3945},[3772,19169,19170],{"class":3949},"avatarUrl",[3772,19172,4806],{"class":3945},[3772,19174,19175],{"class":3774,"line":4023},[3772,19176,19177],{"class":3945},"        }),\n",[3772,19179,19180,19183],{"class":3774,"line":4028},[3772,19181,19182],{"class":3949},"        shallowEqual",[3772,19184,4806],{"class":3945},[3772,19186,19187],{"class":3774,"line":4034},[3772,19188,4310],{"class":3945},[3772,19190,19191],{"class":3774,"line":4068},[3772,19192,3965],{"emptyLinePlaceholder":3964},[3772,19194,19195,19197],{"class":3774,"line":4313},[3772,19196,4210],{"class":3941},[3772,19198,4213],{"class":3945},[3772,19200,19201,19203,19206],{"class":3774,"line":4470},[3772,19202,4219],{"class":4218},[3772,19204,19205],{"class":4042},"View",[3772,19207,4065],{"class":4218},[3772,19209,19210,19212,19214,19216,19218,19220,19222,19224,19226],{"class":3774,"line":4879},[3772,19211,4242],{"class":4218},[3772,19213,14521],{"class":4042},[3772,19215,14780],{"class":4218},[3772,19217,4230],{"class":3980},[3772,19219,4838],{"class":3949},[3772,19221,4235],{"class":3980},[3772,19223,14802],{"class":4218},[3772,19225,14521],{"class":4042},[3772,19227,4065],{"class":4218},[3772,19229,19230,19232,19234],{"class":3774,"line":4892},[3772,19231,4301],{"class":4218},[3772,19233,19205],{"class":4042},[3772,19235,4065],{"class":4218},[3772,19237,19238],{"class":3774,"line":4903},[3772,19239,4310],{"class":3945},[3772,19241,19242],{"class":3774,"line":4909},[3772,19243,4316],{"class":3945},[4495,19245],{},[3747,19247,19249,19250],{"id":19248},"_8-нормалізація-стану-за-допомогою-createentityadapter","8. Нормалізація стану за допомогою ",[3769,19251,19252],{},"createEntityAdapter",[3743,19254,19255,19256,19260,19261,19265,19266,4094],{},"У попередній статті ми з'ясували, чому збереження звичайних масивів з API сповільнює роботу до ",[7424,19257],{":inline":19258,"tex":19259},"true","O(N)",". Redux Toolkit надає потужну вбудовану утиліту ",[3829,19262,19263],{},[3769,19264,19252],{},", яка автоматизує роботу з нормалізованими структурами ",[3769,19267,19268],{},"{ ids: string[], entities: Record\u003Cstring, Entity> }",[3762,19270,19272],{"className":3925,"code":19271,"language":3927,"meta":3767,"style":3767},"import { createSlice, createEntityAdapter } from '@reduxjs\u002Ftoolkit'\nimport type { RootState } from '..\u002Findex'\n\nexport interface Trip {\n    id: string\n    title: string\n    region: string\n    likes: number\n}\n\n\u002F\u002F 1. Створюємо адаптер сутностей з сортуванням за назвою\nexport const tripsAdapter = createEntityAdapter\u003CTrip>({\n    selectId: (trip) => trip.id,\n    sortComparer: (a, b) => a.title.localeCompare(b.title),\n})\n\n\u002F\u002F 2. Отримуємо початковий стан: { ids: [], entities: {} } + кастомні поля\nconst initialState = tripsAdapter.getInitialState({\n    isLoading: false,\n    error: null as string | null,\n})\n\n\u002F\u002F 3. Слайс із вбудованими CRUD-мутаціями адаптера\nexport const tripsNormalizedSlice = createSlice({\n    name: 'tripsNormalized',\n    initialState,\n    reducers: {\n        \u002F\u002F Додавання однієї поїздки зі складністю O(1)\n        addTrip: tripsAdapter.addOne,\n\n        \u002F\u002F Оновлення поїздки зі складністю O(1)\n        updateTripLikes(state, action: { payload: { id: string; likes: number } }) {\n            tripsAdapter.updateOne(state, {\n                id: action.payload.id,\n                changes: { likes: action.payload.likes },\n            })\n        },\n\n        \u002F\u002F Видалення поїздки\n        removeTrip: tripsAdapter.removeOne,\n\n        \u002F\u002F Повне перезаписування списку\n        setAllTrips: tripsAdapter.setAll,\n    },\n})\n\n\u002F\u002F 4. Автоматично згенеровані високопродуктивні селектори\nexport const {\n    selectAll: selectAllNormalizedTrips, \u002F\u002F Повертає впорядкований масив Trip[]\n    selectById: selectNormalizedTripById, \u002F\u002F Вибірка за ID зі складністю O(1)\n    selectIds: selectTripIds, \u002F\u002F Повертає масив id []\n    selectTotal: selectTotalTripsCount, \u002F\u002F Повертає загальну кількість\n} = tripsAdapter.getSelectors((state: RootState) => state.tripsNormalized)\n",[3769,19273,19274,19292,19308,19312,19323,19331,19339,19347,19355,19359,19363,19368,19388,19411,19454,19458,19462,19467,19485,19494,19510,19514,19518,19523,19538,19547,19553,19559,19564,19577,19581,19586,19621,19637,19654,19676,19680,19684,19688,19692,19705,19709,19714,19728,19732,19736,19740,19745,19753,19768,19783,19798,19813],{"__ignoreMap":3767},[3772,19275,19276,19278,19280,19282,19284,19286,19288,19290],{"class":3774,"line":3775},[3772,19277,3942],{"class":3941},[3772,19279,3946],{"class":3945},[3772,19281,3846],{"class":3949},[3772,19283,3847],{"class":3945},[3772,19285,19252],{"class":3949},[3772,19287,3952],{"class":3945},[3772,19289,3955],{"class":3941},[3772,19291,3958],{"class":3781},[3772,19293,19294,19296,19298,19300,19302,19304,19306],{"class":3774,"line":3938},[3772,19295,3942],{"class":3941},[3772,19297,4039],{"class":3941},[3772,19299,3946],{"class":3945},[3772,19301,14962],{"class":3949},[3772,19303,3952],{"class":3945},[3772,19305,3955],{"class":3941},[3772,19307,14969],{"class":3781},[3772,19309,19310],{"class":3774,"line":3961},[3772,19311,3965],{"emptyLinePlaceholder":3964},[3772,19313,19314,19316,19319,19321],{"class":3774,"line":3968},[3772,19315,3977],{"class":3941},[3772,19317,19318],{"class":3980}," interface",[3772,19320,6379],{"class":4042},[3772,19322,4002],{"class":3945},[3772,19324,19325,19327,19329],{"class":3774,"line":3974},[3772,19326,6386],{"class":3949},[3772,19328,4800],{"class":3945},[3772,19330,6391],{"class":4042},[3772,19332,19333,19335,19337],{"class":3774,"line":3996},[3772,19334,6396],{"class":3949},[3772,19336,4800],{"class":3945},[3772,19338,6391],{"class":4042},[3772,19340,19341,19343,19345],{"class":3774,"line":4005},[3772,19342,6405],{"class":3949},[3772,19344,4800],{"class":3945},[3772,19346,6391],{"class":4042},[3772,19348,19349,19351,19353],{"class":3774,"line":4011},[3772,19350,8502],{"class":3949},[3772,19352,4800],{"class":3945},[3772,19354,8507],{"class":4042},[3772,19356,19357],{"class":3774,"line":4017},[3772,19358,4316],{"class":3945},[3772,19360,19361],{"class":3774,"line":4023},[3772,19362,3965],{"emptyLinePlaceholder":3964},[3772,19364,19365],{"class":3774,"line":4028},[3772,19366,19367],{"class":3934},"\u002F\u002F 1. Створюємо адаптер сутностей з сортуванням за назвою\n",[3772,19369,19370,19372,19374,19377,19379,19381,19383,19385],{"class":3774,"line":4034},[3772,19371,3977],{"class":3941},[3772,19373,3981],{"class":3980},[3772,19375,19376],{"class":3984}," tripsAdapter",[3772,19378,3988],{"class":3945},[3772,19380,19252],{"class":3778},[3772,19382,4051],{"class":3945},[3772,19384,6436],{"class":4042},[3772,19386,19387],{"class":3945},">({\n",[3772,19389,19390,19393,19395,19397,19399,19401,19403,19405,19407,19409],{"class":3774,"line":4068},[3772,19391,19392],{"class":3778},"    selectId",[3772,19394,4094],{"class":3949},[3772,19396,5179],{"class":3945},[3772,19398,5762],{"class":3949},[3772,19400,5765],{"class":3945},[3772,19402,5768],{"class":3980},[3772,19404,5788],{"class":3949},[3772,19406,4059],{"class":3945},[3772,19408,5812],{"class":3949},[3772,19410,4806],{"class":3945},[3772,19412,19413,19416,19418,19420,19423,19425,19428,19430,19432,19435,19437,19439,19441,19444,19446,19448,19450,19452],{"class":3774,"line":4313},[3772,19414,19415],{"class":3778},"    sortComparer",[3772,19417,4094],{"class":3949},[3772,19419,5179],{"class":3945},[3772,19421,19422],{"class":3949},"a",[3772,19424,3847],{"class":3945},[3772,19426,19427],{"class":3949},"b",[3772,19429,5765],{"class":3945},[3772,19431,5768],{"class":3980},[3772,19433,19434],{"class":3949}," a",[3772,19436,4059],{"class":3945},[3772,19438,7131],{"class":3949},[3772,19440,4059],{"class":3945},[3772,19442,19443],{"class":3778},"localeCompare",[3772,19445,5150],{"class":3945},[3772,19447,19427],{"class":3949},[3772,19449,4059],{"class":3945},[3772,19451,7131],{"class":3949},[3772,19453,6082],{"class":3945},[3772,19455,19456],{"class":3774,"line":4470},[3772,19457,4020],{"class":3945},[3772,19459,19460],{"class":3774,"line":4879},[3772,19461,3965],{"emptyLinePlaceholder":3964},[3772,19463,19464],{"class":3774,"line":4892},[3772,19465,19466],{"class":3934},"\u002F\u002F 2. Отримуємо початковий стан: { ids: [], entities: {} } + кастомні поля\n",[3772,19468,19469,19471,19473,19475,19478,19480,19483],{"class":3774,"line":4903},[3772,19470,5885],{"class":3980},[3772,19472,5888],{"class":3984},[3772,19474,3988],{"class":3945},[3772,19476,19477],{"class":3949},"tripsAdapter",[3772,19479,4059],{"class":3945},[3772,19481,19482],{"class":3778},"getInitialState",[3772,19484,3993],{"class":3945},[3772,19486,19487,19490,19492],{"class":3774,"line":4909},[3772,19488,19489],{"class":3949},"    isLoading:",[3772,19491,4279],{"class":3980},[3772,19493,4806],{"class":3945},[3772,19495,19496,19498,19500,19502,19504,19506,19508],{"class":3774,"line":5521},[3772,19497,5912],{"class":3949},[3772,19499,5915],{"class":3980},[3772,19501,13221],{"class":3941},[3772,19503,7815],{"class":4042},[3772,19505,6462],{"class":3945},[3772,19507,9870],{"class":4042},[3772,19509,4806],{"class":3945},[3772,19511,19512],{"class":3774,"line":5527},[3772,19513,4020],{"class":3945},[3772,19515,19516],{"class":3774,"line":5533},[3772,19517,3965],{"emptyLinePlaceholder":3964},[3772,19519,19520],{"class":3774,"line":5539},[3772,19521,19522],{"class":3934},"\u002F\u002F 3. Слайс із вбудованими CRUD-мутаціями адаптера\n",[3772,19524,19525,19527,19529,19532,19534,19536],{"class":3774,"line":5545},[3772,19526,3977],{"class":3941},[3772,19528,3981],{"class":3980},[3772,19530,19531],{"class":3984}," tripsNormalizedSlice",[3772,19533,3988],{"class":3945},[3772,19535,3846],{"class":3778},[3772,19537,3993],{"class":3945},[3772,19539,19540,19542,19545],{"class":3774,"line":5550},[3772,19541,6540],{"class":3949},[3772,19543,19544],{"class":3781}," 'tripsNormalized'",[3772,19546,4806],{"class":3945},[3772,19548,19549,19551],{"class":3774,"line":6121},[3772,19550,6550],{"class":3949},[3772,19552,4806],{"class":3945},[3772,19554,19555,19557],{"class":3774,"line":6131},[3772,19556,6557],{"class":3949},[3772,19558,4002],{"class":3945},[3772,19560,19561],{"class":3774,"line":6136},[3772,19562,19563],{"class":3934},"        \u002F\u002F Додавання однієї поїздки зі складністю O(1)\n",[3772,19565,19566,19568,19570,19572,19575],{"class":3774,"line":6142},[3772,19567,9461],{"class":3949},[3772,19569,19376],{"class":3949},[3772,19571,4059],{"class":3945},[3772,19573,19574],{"class":3949},"addOne",[3772,19576,4806],{"class":3945},[3772,19578,19579],{"class":3774,"line":6150},[3772,19580,3965],{"emptyLinePlaceholder":3964},[3772,19582,19583],{"class":3774,"line":6157},[3772,19584,19585],{"class":3934},"        \u002F\u002F Оновлення поїздки зі складністю O(1)\n",[3772,19587,19588,19590,19592,19594,19596,19598,19600,19602,19604,19606,19608,19610,19612,19614,19616,19618],{"class":3774,"line":6162},[3772,19589,8958],{"class":3778},[3772,19591,5150],{"class":3945},[3772,19593,5153],{"class":3949},[3772,19595,3847],{"class":3945},[3772,19597,5163],{"class":3949},[3772,19599,4835],{"class":3945},[3772,19601,5059],{"class":3949},[3772,19603,4835],{"class":3945},[3772,19605,5812],{"class":3949},[3772,19607,4800],{"class":3945},[3772,19609,6459],{"class":4042},[3772,19611,7818],{"class":3945},[3772,19613,8983],{"class":3949},[3772,19615,4800],{"class":3945},[3772,19617,7833],{"class":4042},[3772,19619,19620],{"class":3945}," } }) {\n",[3772,19622,19623,19626,19628,19631,19633,19635],{"class":3774,"line":6629},[3772,19624,19625],{"class":3949},"            tripsAdapter",[3772,19627,4059],{"class":3945},[3772,19629,19630],{"class":3778},"updateOne",[3772,19632,5150],{"class":3945},[3772,19634,5153],{"class":3949},[3772,19636,15192],{"class":3945},[3772,19638,19639,19642,19644,19646,19648,19650,19652],{"class":3774,"line":6653},[3772,19640,19641],{"class":3949},"                id:",[3772,19643,7262],{"class":3949},[3772,19645,4059],{"class":3945},[3772,19647,5059],{"class":3949},[3772,19649,4059],{"class":3945},[3772,19651,5812],{"class":3949},[3772,19653,4806],{"class":3945},[3772,19655,19656,19659,19661,19664,19666,19668,19670,19672,19674],{"class":3774,"line":6698},[3772,19657,19658],{"class":3949},"                changes:",[3772,19660,3946],{"class":3945},[3772,19662,19663],{"class":3949},"likes:",[3772,19665,7262],{"class":3949},[3772,19667,4059],{"class":3945},[3772,19669,5059],{"class":3949},[3772,19671,4059],{"class":3945},[3772,19673,8983],{"class":3949},[3772,19675,4761],{"class":3945},[3772,19677,19678],{"class":3774,"line":6703},[3772,19679,9263],{"class":3945},[3772,19681,19682],{"class":3774,"line":6709},[3772,19683,6621],{"class":3945},[3772,19685,19686],{"class":3774,"line":6734},[3772,19687,3965],{"emptyLinePlaceholder":3964},[3772,19689,19690],{"class":3774,"line":6753},[3772,19691,6626],{"class":3934},[3772,19693,19694,19696,19698,19700,19703],{"class":3774,"line":6758},[3772,19695,9469],{"class":3949},[3772,19697,19376],{"class":3949},[3772,19699,4059],{"class":3945},[3772,19701,19702],{"class":3949},"removeOne",[3772,19704,4806],{"class":3945},[3772,19706,19707],{"class":3774,"line":6763},[3772,19708,3965],{"emptyLinePlaceholder":3964},[3772,19710,19711],{"class":3774,"line":6768},[3772,19712,19713],{"class":3934},"        \u002F\u002F Повне перезаписування списку\n",[3772,19715,19716,19719,19721,19723,19726],{"class":3774,"line":6773},[3772,19717,19718],{"class":3949},"        setAllTrips:",[3772,19720,19376],{"class":3949},[3772,19722,4059],{"class":3945},[3772,19724,19725],{"class":3949},"setAll",[3772,19727,4806],{"class":3945},[3772,19729,19730],{"class":3774,"line":6779},[3772,19731,4014],{"class":3945},[3772,19733,19734],{"class":3774,"line":6812},[3772,19735,4020],{"class":3945},[3772,19737,19738],{"class":3774,"line":6817},[3772,19739,3965],{"emptyLinePlaceholder":3964},[3772,19741,19742],{"class":3774,"line":6823},[3772,19743,19744],{"class":3934},"\u002F\u002F 4. Автоматично згенеровані високопродуктивні селектори\n",[3772,19746,19747,19749,19751],{"class":3774,"line":8841},[3772,19748,3977],{"class":3941},[3772,19750,3981],{"class":3980},[3772,19752,4002],{"class":3945},[3772,19754,19755,19758,19760,19763,19765],{"class":3774,"line":8865},[3772,19756,19757],{"class":3949},"    selectAll",[3772,19759,4800],{"class":3945},[3772,19761,19762],{"class":3984},"selectAllNormalizedTrips",[3772,19764,3847],{"class":3945},[3772,19766,19767],{"class":3934},"\u002F\u002F Повертає впорядкований масив Trip[]\n",[3772,19769,19770,19773,19775,19778,19780],{"class":3774,"line":8873},[3772,19771,19772],{"class":3949},"    selectById",[3772,19774,4800],{"class":3945},[3772,19776,19777],{"class":3984},"selectNormalizedTripById",[3772,19779,3847],{"class":3945},[3772,19781,19782],{"class":3934},"\u002F\u002F Вибірка за ID зі складністю O(1)\n",[3772,19784,19785,19788,19790,19793,19795],{"class":3774,"line":8881},[3772,19786,19787],{"class":3949},"    selectIds",[3772,19789,4800],{"class":3945},[3772,19791,19792],{"class":3984},"selectTripIds",[3772,19794,3847],{"class":3945},[3772,19796,19797],{"class":3934},"\u002F\u002F Повертає масив id []\n",[3772,19799,19800,19803,19805,19808,19810],{"class":3774,"line":8894},[3772,19801,19802],{"class":3949},"    selectTotal",[3772,19804,4800],{"class":3945},[3772,19806,19807],{"class":3984},"selectTotalTripsCount",[3772,19809,3847],{"class":3945},[3772,19811,19812],{"class":3934},"\u002F\u002F Повертає загальну кількість\n",[3772,19814,19815,19818,19820,19822,19825,19827,19829,19831,19833,19835,19837,19839,19841,19844],{"class":3774,"line":8902},[3772,19816,19817],{"class":3945},"} = ",[3772,19819,19477],{"class":3949},[3772,19821,4059],{"class":3945},[3772,19823,19824],{"class":3778},"getSelectors",[3772,19826,6056],{"class":3945},[3772,19828,5153],{"class":3949},[3772,19830,4800],{"class":3945},[3772,19832,14962],{"class":4042},[3772,19834,5765],{"class":3945},[3772,19836,5768],{"class":3980},[3772,19838,5353],{"class":3949},[3772,19840,4059],{"class":3945},[3772,19842,19843],{"class":3949},"tripsNormalized",[3772,19845,5345],{"class":3945},[4495,19847],{},[3747,19849,19851,19852,19854],{"id":19850},"_9-асинхронні-операції-createasyncthunk-у-деталях","9. Асинхронні операції: ",[3769,19853,3853],{}," у деталях",[3743,19856,19857,19858,3847,19861,3847,19864,19867,19868,19872],{},"У класичному Redux виконання асинхронного запиту вимагало ручного створення трьох окремих типів дій (",[3769,19859,19860],{},"FETCH_START",[3769,19862,19863],{},"FETCH_SUCCESS",[3769,19865,19866],{},"FETCH_FAILURE",") та написання функції thunk, яка їх послідовно відправляє. У Redux Toolkit функція ",[3829,19869,19870],{},[3769,19871,3853],{}," автоматизує весь цей життєвий цикл.",[7025,19874,19876],{"id":19875},"що-таке-thunk-та-навіщо-він-потрібен","Що таке Thunk та навіщо він потрібен?",[3743,19878,19879,19882,19883,19886],{},[3829,19880,19881],{},"Thunk"," (з англ. \"відкладене обчислення\") — це функція, яка повертає іншу функцію. У контексті Redux це дозволяє писати ",[3829,19884,19885],{},"асинхронну логіку",", яка взаємодіє зі store.",[3743,19888,19889],{},[3829,19890,19891],{},"Проблема без Thunk:",[3762,19893,19895],{"className":3925,"code":19894,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОМИЛКА: Редюсери НЕ МОЖУТЬ бути асинхронними!\nconst tripsSlice = createSlice({\n    name: 'trips',\n    initialState,\n    reducers: {\n        \u002F\u002F ❌ Це НЕ ПРАЦЮЄ — редюсер має бути синхронним!\n        async loadTrips(state) {\n            const response = await fetch('\u002Fapi\u002Ftrips')\n            state.items = await response.json()\n        },\n    },\n})\n",[3769,19896,19897,19902,19914,19922,19928,19934,19939,19952,19970,19990,19994,19998],{"__ignoreMap":3767},[3772,19898,19899],{"class":3774,"line":3775},[3772,19900,19901],{"class":3934},"\u002F\u002F ❌ ПОМИЛКА: Редюсери НЕ МОЖУТЬ бути асинхронними!\n",[3772,19903,19904,19906,19908,19910,19912],{"class":3774,"line":3938},[3772,19905,5885],{"class":3980},[3772,19907,6529],{"class":3984},[3772,19909,3988],{"class":3945},[3772,19911,3846],{"class":3778},[3772,19913,3993],{"class":3945},[3772,19915,19916,19918,19920],{"class":3774,"line":3961},[3772,19917,6540],{"class":3949},[3772,19919,6543],{"class":3781},[3772,19921,4806],{"class":3945},[3772,19923,19924,19926],{"class":3774,"line":3968},[3772,19925,6550],{"class":3949},[3772,19927,4806],{"class":3945},[3772,19929,19930,19932],{"class":3774,"line":3974},[3772,19931,6557],{"class":3949},[3772,19933,4002],{"class":3945},[3772,19935,19936],{"class":3774,"line":3996},[3772,19937,19938],{"class":3934},"        \u002F\u002F ❌ Це НЕ ПРАЦЮЄ — редюсер має бути синхронним!\n",[3772,19940,19941,19944,19946,19948,19950],{"class":3774,"line":4005},[3772,19942,19943],{"class":3980},"        async",[3772,19945,16749],{"class":3778},[3772,19947,5150],{"class":3945},[3772,19949,5153],{"class":3949},[3772,19951,5166],{"class":3945},[3772,19953,19954,19956,19958,19960,19962,19964,19966,19968],{"class":3774,"line":4011},[3772,19955,8995],{"class":3980},[3772,19957,15161],{"class":3984},[3772,19959,3988],{"class":3945},[3772,19961,15166],{"class":3941},[3772,19963,16769],{"class":3778},[3772,19965,5150],{"class":3945},[3772,19967,16774],{"class":3781},[3772,19969,5345],{"class":3945},[3772,19971,19972,19974,19976,19978,19980,19982,19984,19986,19988],{"class":3774,"line":4017},[3772,19973,6598],{"class":3949},[3772,19975,4059],{"class":3945},[3772,19977,5237],{"class":3949},[3772,19979,3988],{"class":3945},[3772,19981,15166],{"class":3941},[3772,19983,15161],{"class":3949},[3772,19985,4059],{"class":3945},[3772,19987,16868],{"class":3778},[3772,19989,13941],{"class":3945},[3772,19991,19992],{"class":3774,"line":4023},[3772,19993,6621],{"class":3945},[3772,19995,19996],{"class":3774,"line":4028},[3772,19997,4014],{"class":3945},[3772,19999,20000],{"class":3774,"line":4034},[3772,20001,4020],{"class":3945},[3743,20003,20004],{},[3829,20005,20006],{},"Рішення: createAsyncThunk",[3743,20008,20009,20011],{},[3769,20010,3853],{}," — це утиліта, яка створює спеціальну функцію, котра:",[4588,20013,20014,20025,20031],{},[3836,20015,20016,5179,20019,3847,20021,3847,20023,4669],{},[3829,20017,20018],{},"Автоматично генерує 3 типи дій",[3769,20020,9234],{},[3769,20022,9279],{},[3769,20024,12260],{},[3836,20026,20027,20030],{},[3829,20028,20029],{},"Виконує асинхронний код"," (HTTP-запити, читання з бази даних)",[3836,20032,20033,20036],{},[3829,20034,20035],{},"Диспатчить відповідні дії"," залежно від результату",[3762,20038,20040],{"className":3925,"code":20039,"language":3927,"meta":3767,"style":3767},"import { createAsyncThunk } from '@reduxjs\u002Ftoolkit'\n\n\u002F\u002F createAsyncThunk автоматично створює:\n\u002F\u002F - fetchTrips.pending    → 'trips\u002FfetchTrips\u002Fpending'\n\u002F\u002F - fetchTrips.fulfilled  → 'trips\u002FfetchTrips\u002Ffulfilled'\n\u002F\u002F - fetchTrips.rejected   → 'trips\u002FfetchTrips\u002Frejected'\n\nexport const fetchTrips = createAsyncThunk(\n    'trips\u002FfetchTrips', \u002F\u002F Префікс для типів дій\n    async () => {\n        \u002F\u002F Асинхронна функція (payload creator)\n        const response = await fetch('\u002Fapi\u002Ftrips')\n        return response.json() \u002F\u002F Це стане payload у fulfilled дії\n    },\n)\n",[3769,20041,20042,20056,20060,20065,20070,20075,20080,20084,20099,20109,20119,20124,20142,20158,20162],{"__ignoreMap":3767},[3772,20043,20044,20046,20048,20050,20052,20054],{"class":3774,"line":3775},[3772,20045,3942],{"class":3941},[3772,20047,3946],{"class":3945},[3772,20049,3853],{"class":3949},[3772,20051,3952],{"class":3945},[3772,20053,3955],{"class":3941},[3772,20055,3958],{"class":3781},[3772,20057,20058],{"class":3774,"line":3938},[3772,20059,3965],{"emptyLinePlaceholder":3964},[3772,20061,20062],{"class":3774,"line":3961},[3772,20063,20064],{"class":3934},"\u002F\u002F createAsyncThunk автоматично створює:\n",[3772,20066,20067],{"class":3774,"line":3968},[3772,20068,20069],{"class":3934},"\u002F\u002F - fetchTrips.pending    → 'trips\u002FfetchTrips\u002Fpending'\n",[3772,20071,20072],{"class":3774,"line":3974},[3772,20073,20074],{"class":3934},"\u002F\u002F - fetchTrips.fulfilled  → 'trips\u002FfetchTrips\u002Ffulfilled'\n",[3772,20076,20077],{"class":3774,"line":3996},[3772,20078,20079],{"class":3934},"\u002F\u002F - fetchTrips.rejected   → 'trips\u002FfetchTrips\u002Frejected'\n",[3772,20081,20082],{"class":3774,"line":4005},[3772,20083,3965],{"emptyLinePlaceholder":3964},[3772,20085,20086,20088,20090,20093,20095,20097],{"class":3774,"line":4011},[3772,20087,3977],{"class":3941},[3772,20089,3981],{"class":3980},[3772,20091,20092],{"class":3984}," fetchTrips",[3772,20094,3988],{"class":3945},[3772,20096,3853],{"class":3778},[3772,20098,12904],{"class":3945},[3772,20100,20101,20104,20106],{"class":3774,"line":4017},[3772,20102,20103],{"class":3781},"    'trips\u002FfetchTrips'",[3772,20105,3847],{"class":3945},[3772,20107,20108],{"class":3934},"\u002F\u002F Префікс для типів дій\n",[3772,20110,20111,20113,20115,20117],{"class":3774,"line":4023},[3772,20112,16746],{"class":3980},[3772,20114,16835],{"class":3945},[3772,20116,5768],{"class":3980},[3772,20118,4002],{"class":3945},[3772,20120,20121],{"class":3774,"line":4028},[3772,20122,20123],{"class":3934},"        \u002F\u002F Асинхронна функція (payload creator)\n",[3772,20125,20126,20128,20130,20132,20134,20136,20138,20140],{"class":3774,"line":4034},[3772,20127,10557],{"class":3980},[3772,20129,15161],{"class":3984},[3772,20131,3988],{"class":3945},[3772,20133,15166],{"class":3941},[3772,20135,16769],{"class":3778},[3772,20137,5150],{"class":3945},[3772,20139,16774],{"class":3781},[3772,20141,5345],{"class":3945},[3772,20143,20144,20146,20148,20150,20152,20155],{"class":3774,"line":4068},[3772,20145,5202],{"class":3941},[3772,20147,15161],{"class":3949},[3772,20149,4059],{"class":3945},[3772,20151,16868],{"class":3778},[3772,20153,20154],{"class":3945},"() ",[3772,20156,20157],{"class":3934},"\u002F\u002F Це стане payload у fulfilled дії\n",[3772,20159,20160],{"class":3774,"line":4313},[3772,20161,4014],{"class":3945},[3772,20163,20164],{"class":3774,"line":4470},[3772,20165,5345],{"class":3945},[7025,20167,20169],{"id":20168},"життєвий-цикл-createasyncthunk-покрокове-пояснення","Життєвий цикл createAsyncThunk: Покрокове пояснення",[3743,20171,20172,20173,20176],{},"Коли ви викликаєте ",[3769,20174,20175],{},"dispatch(fetchTrips())",", відбувається наступна послідовність:",[5417,20178,20180],{"alt":20179},"Життєвий цикл createAsyncThunk",[3762,20181,20183],{"className":5422,"code":20182,"language":5424,"meta":3767,"style":3767},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam defaultFontName \"Helvetica\"\n\nactor \"Компонент\" as Component #DBEAFE\nparticipant \"dispatch()\" as Dispatch #FEF08A\nparticipant \"createAsyncThunk\" as Thunk #FED7AA\nparticipant \"HTTP API\" as API #DCFCE7\nparticipant \"extraReducers\" as Reducer #E0E7FF\ndatabase \"Redux Store\" as Store #FEF3C7\n\nComponent -> Dispatch : 1. dispatch(fetchTrips())\nDispatch -> Thunk : 2. Виклик thunk функції\nThunk -> Reducer : 3. Відправка PENDING дії\nnote right\n    type: 'trips\u002FfetchTrips\u002Fpending'\n    payload: undefined\n    meta: { requestId, arg }\nend note\nReducer -> Store : 4. loading = true\nStore -> Component : 5. Компонент показує Loader\n\nThunk -> API : 6. await fetch('\u002Fapi\u002Ftrips')\nAPI --> Thunk : 7. Відповідь: { trips: [...] }\n\nalt Успішний запит\n    Thunk -> Reducer : 8a. Відправка FULFILLED дії\n    note right\n        type: 'trips\u002FfetchTrips\u002Ffulfilled'\n        payload: { trips: [...] }\n    end note\n    Reducer -> Store : 9a. items = payload, loading = false\n    Store -> Component : 10a. Рендер списку поїздок\nelse Помилка запиту\n    Thunk -> Reducer : 8b. Відправка REJECTED дії\n    note right\n        type: 'trips\u002FfetchTrips\u002Frejected'\n        error: { message: \"Network error\" }\n        payload: (якщо rejectWithValue)\n    end note\n    Reducer -> Store : 9b. error = message, loading = false\n    Store -> Component : 10b. Показ повідомлення про помилку\nend\n\n@enduml\n",[3769,20184,20185,20189,20193,20197,20201,20205,20210,20215,20220,20225,20230,20235,20239,20244,20249,20254,20258,20263,20268,20273,20277,20282,20287,20291,20296,20301,20305,20310,20315,20320,20325,20330,20335,20340,20345,20350,20355,20359,20364,20369,20374,20378,20383,20388,20393,20397],{"__ignoreMap":3767},[3772,20186,20187],{"class":3774,"line":3775},[3772,20188,5431],{},[3772,20190,20191],{"class":3774,"line":3938},[3772,20192,5436],{},[3772,20194,20195],{"class":3774,"line":3961},[3772,20196,5441],{},[3772,20198,20199],{"class":3774,"line":3968},[3772,20200,5446],{},[3772,20202,20203],{"class":3774,"line":3974},[3772,20204,3965],{"emptyLinePlaceholder":3964},[3772,20206,20207],{"class":3774,"line":3996},[3772,20208,20209],{},"actor \"Компонент\" as Component #DBEAFE\n",[3772,20211,20212],{"class":3774,"line":4005},[3772,20213,20214],{},"participant \"dispatch()\" as Dispatch #FEF08A\n",[3772,20216,20217],{"class":3774,"line":4011},[3772,20218,20219],{},"participant \"createAsyncThunk\" as Thunk #FED7AA\n",[3772,20221,20222],{"class":3774,"line":4017},[3772,20223,20224],{},"participant \"HTTP API\" as API #DCFCE7\n",[3772,20226,20227],{"class":3774,"line":4023},[3772,20228,20229],{},"participant \"extraReducers\" as Reducer #E0E7FF\n",[3772,20231,20232],{"class":3774,"line":4028},[3772,20233,20234],{},"database \"Redux Store\" as Store #FEF3C7\n",[3772,20236,20237],{"class":3774,"line":4034},[3772,20238,3965],{"emptyLinePlaceholder":3964},[3772,20240,20241],{"class":3774,"line":4068},[3772,20242,20243],{},"Component -> Dispatch : 1. dispatch(fetchTrips())\n",[3772,20245,20246],{"class":3774,"line":4313},[3772,20247,20248],{},"Dispatch -> Thunk : 2. Виклик thunk функції\n",[3772,20250,20251],{"class":3774,"line":4470},[3772,20252,20253],{},"Thunk -> Reducer : 3. Відправка PENDING дії\n",[3772,20255,20256],{"class":3774,"line":4879},[3772,20257,16223],{},[3772,20259,20260],{"class":3774,"line":4892},[3772,20261,20262],{},"    type: 'trips\u002FfetchTrips\u002Fpending'\n",[3772,20264,20265],{"class":3774,"line":4903},[3772,20266,20267],{},"    payload: undefined\n",[3772,20269,20270],{"class":3774,"line":4909},[3772,20271,20272],{},"    meta: { requestId, arg }\n",[3772,20274,20275],{"class":3774,"line":5521},[3772,20276,5542],{},[3772,20278,20279],{"class":3774,"line":5527},[3772,20280,20281],{},"Reducer -> Store : 4. loading = true\n",[3772,20283,20284],{"class":3774,"line":5533},[3772,20285,20286],{},"Store -> Component : 5. Компонент показує Loader\n",[3772,20288,20289],{"class":3774,"line":5539},[3772,20290,3965],{"emptyLinePlaceholder":3964},[3772,20292,20293],{"class":3774,"line":5545},[3772,20294,20295],{},"Thunk -> API : 6. await fetch('\u002Fapi\u002Ftrips')\n",[3772,20297,20298],{"class":3774,"line":5550},[3772,20299,20300],{},"API --> Thunk : 7. Відповідь: { trips: [...] }\n",[3772,20302,20303],{"class":3774,"line":6121},[3772,20304,3965],{"emptyLinePlaceholder":3964},[3772,20306,20307],{"class":3774,"line":6131},[3772,20308,20309],{},"alt Успішний запит\n",[3772,20311,20312],{"class":3774,"line":6136},[3772,20313,20314],{},"    Thunk -> Reducer : 8a. Відправка FULFILLED дії\n",[3772,20316,20317],{"class":3774,"line":6142},[3772,20318,20319],{},"    note right\n",[3772,20321,20322],{"class":3774,"line":6150},[3772,20323,20324],{},"        type: 'trips\u002FfetchTrips\u002Ffulfilled'\n",[3772,20326,20327],{"class":3774,"line":6157},[3772,20328,20329],{},"        payload: { trips: [...] }\n",[3772,20331,20332],{"class":3774,"line":6162},[3772,20333,20334],{},"    end note\n",[3772,20336,20337],{"class":3774,"line":6629},[3772,20338,20339],{},"    Reducer -> Store : 9a. items = payload, loading = false\n",[3772,20341,20342],{"class":3774,"line":6653},[3772,20343,20344],{},"    Store -> Component : 10a. Рендер списку поїздок\n",[3772,20346,20347],{"class":3774,"line":6698},[3772,20348,20349],{},"else Помилка запиту\n",[3772,20351,20352],{"class":3774,"line":6703},[3772,20353,20354],{},"    Thunk -> Reducer : 8b. Відправка REJECTED дії\n",[3772,20356,20357],{"class":3774,"line":6709},[3772,20358,20319],{},[3772,20360,20361],{"class":3774,"line":6734},[3772,20362,20363],{},"        type: 'trips\u002FfetchTrips\u002Frejected'\n",[3772,20365,20366],{"class":3774,"line":6753},[3772,20367,20368],{},"        error: { message: \"Network error\" }\n",[3772,20370,20371],{"class":3774,"line":6758},[3772,20372,20373],{},"        payload: (якщо rejectWithValue)\n",[3772,20375,20376],{"class":3774,"line":6763},[3772,20377,20334],{},[3772,20379,20380],{"class":3774,"line":6768},[3772,20381,20382],{},"    Reducer -> Store : 9b. error = message, loading = false\n",[3772,20384,20385],{"class":3774,"line":6773},[3772,20386,20387],{},"    Store -> Component : 10b. Показ повідомлення про помилку\n",[3772,20389,20390],{"class":3774,"line":6779},[3772,20391,20392],{},"end\n",[3772,20394,20395],{"class":3774,"line":6812},[3772,20396,3965],{"emptyLinePlaceholder":3964},[3772,20398,20399],{"class":3774,"line":6817},[3772,20400,5553],{},[7025,20402,20404],{"id":20403},"анатомія-createasyncthunk-всі-параметри","Анатомія createAsyncThunk: Всі параметри",[3762,20406,20408],{"className":3925,"code":20407,"language":3927,"meta":3767,"style":3767},"const myThunk = createAsyncThunk\u003C\n    ReturnType, \u002F\u002F Тип успішного результату (fulfilled payload)\n    ArgType, \u002F\u002F Тип вхідного аргументу\n    ThunkApiConfig \u002F\u002F Конфігурація (state, dispatch, rejectValue тощо)\n>(\n    'slice\u002FactionName', \u002F\u002F 1. Префікс типу дії\n    payloadCreator, \u002F\u002F 2. Асинхронна функція\n    options, \u002F\u002F 3. Додаткові опції (condition, dispatchConditionRejection)\n)\n",[3769,20409,20410,20423,20433,20443,20451,20456,20466,20476,20486],{"__ignoreMap":3767},[3772,20411,20412,20414,20417,20419,20421],{"class":3774,"line":3775},[3772,20413,5885],{"class":3980},[3772,20415,20416],{"class":3984}," myThunk",[3772,20418,3988],{"class":3945},[3772,20420,3853],{"class":3949},[3772,20422,14989],{"class":3945},[3772,20424,20425,20428,20430],{"class":3774,"line":3938},[3772,20426,20427],{"class":3949},"    ReturnType",[3772,20429,3847],{"class":3945},[3772,20431,20432],{"class":3934},"\u002F\u002F Тип успішного результату (fulfilled payload)\n",[3772,20434,20435,20438,20440],{"class":3774,"line":3961},[3772,20436,20437],{"class":3949},"    ArgType",[3772,20439,3847],{"class":3945},[3772,20441,20442],{"class":3934},"\u002F\u002F Тип вхідного аргументу\n",[3772,20444,20445,20448],{"class":3774,"line":3968},[3772,20446,20447],{"class":3949},"    ThunkApiConfig",[3772,20449,20450],{"class":3934}," \u002F\u002F Конфігурація (state, dispatch, rejectValue тощо)\n",[3772,20452,20453],{"class":3774,"line":3974},[3772,20454,20455],{"class":3945},">(\n",[3772,20457,20458,20461,20463],{"class":3774,"line":3996},[3772,20459,20460],{"class":3781},"    'slice\u002FactionName'",[3772,20462,3847],{"class":3945},[3772,20464,20465],{"class":3934},"\u002F\u002F 1. Префікс типу дії\n",[3772,20467,20468,20471,20473],{"class":3774,"line":4005},[3772,20469,20470],{"class":3949},"    payloadCreator",[3772,20472,3847],{"class":3945},[3772,20474,20475],{"class":3934},"\u002F\u002F 2. Асинхронна функція\n",[3772,20477,20478,20481,20483],{"class":3774,"line":4011},[3772,20479,20480],{"class":3949},"    options",[3772,20482,3847],{"class":3945},[3772,20484,20485],{"class":3934},"\u002F\u002F 3. Додаткові опції (condition, dispatchConditionRejection)\n",[3772,20487,20488],{"class":3774,"line":4017},[3772,20489,5345],{"class":3945},[3743,20491,20492],{},[3829,20493,20494],{},"Детальний розбір кожного параметра:",[3762,20496,20498],{"className":3925,"code":20497,"language":3927,"meta":3767,"style":3767},"export const fetchTripById = createAsyncThunk\u003C\n    \u002F\u002F 1️⃣ ReturnType — тип даних, які повертаємо при успіху\n    Trip,\n    \u002F\u002F 2️⃣ ArgType — тип аргументу, який передаємо при виклику\n    string, \u002F\u002F tripId\n    \u002F\u002F 3️⃣ ThunkApiConfig — конфігурація для TypeScript\n    {\n        state: RootState \u002F\u002F Доступ до getState()\n        dispatch: AppDispatch \u002F\u002F Типізований dispatch\n        rejectValue: string \u002F\u002F Тип payload при rejectWithValue()\n    }\n>(\n    \u002F\u002F Префікс дії (обов'язковий)\n    'trips\u002FfetchById',\n\n    \u002F\u002F Payload Creator — асинхронна функція (обов'язкова)\n    async (tripId: string, thunkAPI) => {\n        \u002F\u002F thunkAPI надає корисні методи:\n        \u002F\u002F - getState()    → поточний стан store\n        \u002F\u002F - dispatch()    → відправка інших дій\n        \u002F\u002F - extra         → додаткові аргументи (наприклад, API client)\n        \u002F\u002F - requestId     → унікальний ID запиту\n        \u002F\u002F - signal        → AbortSignal для скасування\n        \u002F\u002F - rejectWithValue() → повернення кастомної помилки\n\n        try {\n            const response = await fetch(`\u002Fapi\u002Ftrips\u002F${tripId}`, {\n                signal: thunkAPI.signal, \u002F\u002F Для скасування запиту\n            })\n\n            if (!response.ok) {\n                \u002F\u002F Кастомна обробка помилки\n                return thunkAPI.rejectWithValue('Поїздку не знайдено')\n            }\n\n            const data = await response.json()\n            return data \u002F\u002F Стане payload у fulfilled дії\n        } catch (error) {\n            \u002F\u002F Автоматична обробка помилки\n            return thunkAPI.rejectWithValue(error.message)\n        }\n    },\n\n    \u002F\u002F Options — додаткові налаштування (опціонально)\n    {\n        \u002F\u002F Умова виконання (guard condition)\n        condition: (tripId, { getState }) => {\n            const { loading } = getState().trips\n            \u002F\u002F Запобігаємо повторному запиту, якщо вже завантажуємо\n            if (loading) {\n                return false \u002F\u002F Thunk не виконається\n            }\n            return true\n        },\n\n        \u002F\u002F Чи відправляти rejected дію при condition = false?\n        dispatchConditionRejection: false,\n    },\n)\n",[3769,20499,20500,20515,20520,20527,20532,20542,20547,20551,20562,20573,20584,20588,20592,20597,20604,20608,20613,20636,20641,20646,20651,20656,20661,20666,20671,20675,20682,20709,20727,20731,20735,20752,20757,20774,20778,20782,20800,20809,20822,20827,20847,20851,20855,20859,20864,20868,20873,20895,20912,20917,20927,20936,20940,20947,20951,20955,20960,20969,20973],{"__ignoreMap":3767},[3772,20501,20502,20504,20506,20509,20511,20513],{"class":3774,"line":3775},[3772,20503,3977],{"class":3941},[3772,20505,3981],{"class":3980},[3772,20507,20508],{"class":3984}," fetchTripById",[3772,20510,3988],{"class":3945},[3772,20512,3853],{"class":3949},[3772,20514,14989],{"class":3945},[3772,20516,20517],{"class":3774,"line":3938},[3772,20518,20519],{"class":3934},"    \u002F\u002F 1️⃣ ReturnType — тип даних, які повертаємо при успіху\n",[3772,20521,20522,20525],{"class":3774,"line":3961},[3772,20523,20524],{"class":3949},"    Trip",[3772,20526,4806],{"class":3945},[3772,20528,20529],{"class":3774,"line":3968},[3772,20530,20531],{"class":3934},"    \u002F\u002F 2️⃣ ArgType — тип аргументу, який передаємо при виклику\n",[3772,20533,20534,20537,20539],{"class":3774,"line":3974},[3772,20535,20536],{"class":3949},"    string",[3772,20538,3847],{"class":3945},[3772,20540,20541],{"class":3934},"\u002F\u002F tripId\n",[3772,20543,20544],{"class":3774,"line":3996},[3772,20545,20546],{"class":3934},"    \u002F\u002F 3️⃣ ThunkApiConfig — конфігурація для TypeScript\n",[3772,20548,20549],{"class":3774,"line":4005},[3772,20550,15034],{"class":3945},[3772,20552,20553,20555,20557,20559],{"class":3774,"line":4011},[3772,20554,9935],{"class":4719},[3772,20556,4800],{"class":3945},[3772,20558,14962],{"class":3949},[3772,20560,20561],{"class":3934}," \u002F\u002F Доступ до getState()\n",[3772,20563,20564,20566,20568,20570],{"class":3774,"line":4017},[3772,20565,14715],{"class":4719},[3772,20567,4800],{"class":3945},[3772,20569,17675],{"class":3949},[3772,20571,20572],{"class":3934}," \u002F\u002F Типізований dispatch\n",[3772,20574,20575,20577,20579,20581],{"class":3774,"line":4023},[3772,20576,15048],{"class":4719},[3772,20578,4800],{"class":3945},[3772,20580,6459],{"class":3949},[3772,20582,20583],{"class":3934}," \u002F\u002F Тип payload при rejectWithValue()\n",[3772,20585,20586],{"class":3774,"line":4028},[3772,20587,4906],{"class":3945},[3772,20589,20590],{"class":3774,"line":4034},[3772,20591,20455],{"class":3945},[3772,20593,20594],{"class":3774,"line":4068},[3772,20595,20596],{"class":3934},"    \u002F\u002F Префікс дії (обов'язковий)\n",[3772,20598,20599,20602],{"class":3774,"line":4313},[3772,20600,20601],{"class":3781},"    'trips\u002FfetchById'",[3772,20603,4806],{"class":3945},[3772,20605,20606],{"class":3774,"line":4470},[3772,20607,3965],{"emptyLinePlaceholder":3964},[3772,20609,20610],{"class":3774,"line":4879},[3772,20611,20612],{"class":3934},"    \u002F\u002F Payload Creator — асинхронна функція (обов'язкова)\n",[3772,20614,20615,20617,20619,20621,20623,20625,20627,20630,20632,20634],{"class":3774,"line":4892},[3772,20616,16746],{"class":3980},[3772,20618,5179],{"class":3945},[3772,20620,7598],{"class":3949},[3772,20622,4800],{"class":3945},[3772,20624,6459],{"class":4042},[3772,20626,3847],{"class":3945},[3772,20628,20629],{"class":3949},"thunkAPI",[3772,20631,5765],{"class":3945},[3772,20633,5768],{"class":3980},[3772,20635,4002],{"class":3945},[3772,20637,20638],{"class":3774,"line":4903},[3772,20639,20640],{"class":3934},"        \u002F\u002F thunkAPI надає корисні методи:\n",[3772,20642,20643],{"class":3774,"line":4909},[3772,20644,20645],{"class":3934},"        \u002F\u002F - getState()    → поточний стан store\n",[3772,20647,20648],{"class":3774,"line":5521},[3772,20649,20650],{"class":3934},"        \u002F\u002F - dispatch()    → відправка інших дій\n",[3772,20652,20653],{"class":3774,"line":5527},[3772,20654,20655],{"class":3934},"        \u002F\u002F - extra         → додаткові аргументи (наприклад, API client)\n",[3772,20657,20658],{"class":3774,"line":5533},[3772,20659,20660],{"class":3934},"        \u002F\u002F - requestId     → унікальний ID запиту\n",[3772,20662,20663],{"class":3774,"line":5539},[3772,20664,20665],{"class":3934},"        \u002F\u002F - signal        → AbortSignal для скасування\n",[3772,20667,20668],{"class":3774,"line":5545},[3772,20669,20670],{"class":3934},"        \u002F\u002F - rejectWithValue() → повернення кастомної помилки\n",[3772,20672,20673],{"class":3774,"line":5550},[3772,20674,3965],{"emptyLinePlaceholder":3964},[3772,20676,20677,20680],{"class":3774,"line":6121},[3772,20678,20679],{"class":3941},"        try",[3772,20681,4002],{"class":3945},[3772,20683,20684,20686,20688,20690,20692,20694,20696,20699,20701,20703,20705,20707],{"class":3774,"line":6131},[3772,20685,8995],{"class":3980},[3772,20687,15161],{"class":3984},[3772,20689,3988],{"class":3945},[3772,20691,15166],{"class":3941},[3772,20693,16769],{"class":3778},[3772,20695,5150],{"class":3945},[3772,20697,20698],{"class":3781},"`\u002Fapi\u002Ftrips\u002F",[3772,20700,15182],{"class":3980},[3772,20702,7598],{"class":3949},[3772,20704,4235],{"class":3980},[3772,20706,17171],{"class":3781},[3772,20708,15192],{"class":3945},[3772,20710,20711,20714,20717,20719,20722,20724],{"class":3774,"line":6136},[3772,20712,20713],{"class":3949},"                signal:",[3772,20715,20716],{"class":3949}," thunkAPI",[3772,20718,4059],{"class":3945},[3772,20720,20721],{"class":3949},"signal",[3772,20723,3847],{"class":3945},[3772,20725,20726],{"class":3934},"\u002F\u002F Для скасування запиту\n",[3772,20728,20729],{"class":3774,"line":6142},[3772,20730,9263],{"class":3945},[3772,20732,20733],{"class":3774,"line":6150},[3772,20734,3965],{"emptyLinePlaceholder":3964},[3772,20736,20737,20739,20742,20745,20747,20750],{"class":3774,"line":6157},[3772,20738,9043],{"class":3941},[3772,20740,20741],{"class":3945}," (!",[3772,20743,20744],{"class":3949},"response",[3772,20746,4059],{"class":3945},[3772,20748,20749],{"class":3949},"ok",[3772,20751,5166],{"class":3945},[3772,20753,20754],{"class":3774,"line":6162},[3772,20755,20756],{"class":3934},"                \u002F\u002F Кастомна обробка помилки\n",[3772,20758,20759,20761,20763,20765,20767,20769,20772],{"class":3774,"line":6629},[3772,20760,8868],{"class":3941},[3772,20762,20716],{"class":3949},[3772,20764,4059],{"class":3945},[3772,20766,15099],{"class":3778},[3772,20768,5150],{"class":3945},[3772,20770,20771],{"class":3781},"'Поїздку не знайдено'",[3772,20773,5345],{"class":3945},[3772,20775,20776],{"class":3774,"line":6653},[3772,20777,6016],{"class":3945},[3772,20779,20780],{"class":3774,"line":6698},[3772,20781,3965],{"emptyLinePlaceholder":3964},[3772,20783,20784,20786,20788,20790,20792,20794,20796,20798],{"class":3774,"line":6703},[3772,20785,8995],{"class":3980},[3772,20787,16762],{"class":3984},[3772,20789,3988],{"class":3945},[3772,20791,15166],{"class":3941},[3772,20793,15161],{"class":3949},[3772,20795,4059],{"class":3945},[3772,20797,16868],{"class":3778},[3772,20799,13941],{"class":3945},[3772,20801,20802,20804,20806],{"class":3774,"line":6709},[3772,20803,5977],{"class":3941},[3772,20805,16762],{"class":3949},[3772,20807,20808],{"class":3934}," \u002F\u002F Стане payload у fulfilled дії\n",[3772,20810,20811,20814,20816,20818,20820],{"class":3774,"line":6734},[3772,20812,20813],{"class":3945},"        } ",[3772,20815,15259],{"class":3941},[3772,20817,5179],{"class":3945},[3772,20819,5072],{"class":3949},[3772,20821,5166],{"class":3945},[3772,20823,20824],{"class":3774,"line":6753},[3772,20825,20826],{"class":3934},"            \u002F\u002F Автоматична обробка помилки\n",[3772,20828,20829,20831,20833,20835,20837,20839,20841,20843,20845],{"class":3774,"line":6758},[3772,20830,5977],{"class":3941},[3772,20832,20716],{"class":3949},[3772,20834,4059],{"class":3945},[3772,20836,15099],{"class":3778},[3772,20838,5150],{"class":3945},[3772,20840,5072],{"class":3949},[3772,20842,4059],{"class":3945},[3772,20844,13237],{"class":3949},[3772,20846,5345],{"class":3945},[3772,20848,20849],{"class":3774,"line":6763},[3772,20850,5245],{"class":3945},[3772,20852,20853],{"class":3774,"line":6768},[3772,20854,4014],{"class":3945},[3772,20856,20857],{"class":3774,"line":6773},[3772,20858,3965],{"emptyLinePlaceholder":3964},[3772,20860,20861],{"class":3774,"line":6779},[3772,20862,20863],{"class":3934},"    \u002F\u002F Options — додаткові налаштування (опціонально)\n",[3772,20865,20866],{"class":3774,"line":6812},[3772,20867,15034],{"class":3945},[3772,20869,20870],{"class":3774,"line":6817},[3772,20871,20872],{"class":3934},"        \u002F\u002F Умова виконання (guard condition)\n",[3772,20874,20875,20878,20880,20882,20884,20887,20889,20891,20893],{"class":3774,"line":6823},[3772,20876,20877],{"class":3778},"        condition",[3772,20879,4094],{"class":3949},[3772,20881,5179],{"class":3945},[3772,20883,7598],{"class":3949},[3772,20885,20886],{"class":3945},", { ",[3772,20888,4062],{"class":3949},[3772,20890,15102],{"class":3945},[3772,20892,5768],{"class":3980},[3772,20894,4002],{"class":3945},[3772,20896,20897,20899,20901,20903,20905,20907,20909],{"class":3774,"line":8841},[3772,20898,8995],{"class":3980},[3772,20900,3946],{"class":3945},[3772,20902,6741],{"class":3984},[3772,20904,6801],{"class":3945},[3772,20906,4062],{"class":3778},[3772,20908,7205],{"class":3945},[3772,20910,20911],{"class":3949},"trips\n",[3772,20913,20914],{"class":3774,"line":8865},[3772,20915,20916],{"class":3934},"            \u002F\u002F Запобігаємо повторному запиту, якщо вже завантажуємо\n",[3772,20918,20919,20921,20923,20925],{"class":3774,"line":8873},[3772,20920,9043],{"class":3941},[3772,20922,5179],{"class":3945},[3772,20924,6741],{"class":3949},[3772,20926,5166],{"class":3945},[3772,20928,20929,20931,20933],{"class":3774,"line":8881},[3772,20930,8868],{"class":3941},[3772,20932,4279],{"class":3980},[3772,20934,20935],{"class":3934}," \u002F\u002F Thunk не виконається\n",[3772,20937,20938],{"class":3774,"line":8894},[3772,20939,6016],{"class":3945},[3772,20941,20942,20944],{"class":3774,"line":8902},[3772,20943,5977],{"class":3941},[3772,20945,20946],{"class":3980}," true\n",[3772,20948,20949],{"class":3774,"line":8910},[3772,20950,6621],{"class":3945},[3772,20952,20953],{"class":3774,"line":8922},[3772,20954,3965],{"emptyLinePlaceholder":3964},[3772,20956,20957],{"class":3774,"line":8928},[3772,20958,20959],{"class":3934},"        \u002F\u002F Чи відправляти rejected дію при condition = false?\n",[3772,20961,20962,20965,20967],{"class":3774,"line":8934},[3772,20963,20964],{"class":3949},"        dispatchConditionRejection:",[3772,20966,4279],{"class":3980},[3772,20968,4806],{"class":3945},[3772,20970,20971],{"class":3774,"line":8939},[3772,20972,4014],{"class":3945},[3772,20974,20975],{"class":3774,"line":8944},[3772,20976,5345],{"class":3945},[7025,20978,20980],{"id":20979},"три-стани-життєвого-циклу-pending-fulfilled-rejected","Три стани життєвого циклу: pending, fulfilled, rejected",[3743,20982,20983,20984,20986,20987,4094],{},"Кожен ",[3769,20985,3853],{}," генерує ",[3829,20988,20989],{},"три автоматичні дії",[5629,20991,20992,21122,21303],{},[3762,20993,20996],{"className":3925,"code":20994,"filename":20995,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Відправляється автоматично при виклику thunk\n{\n    type: 'trips\u002FfetchTrips\u002Fpending',\n    meta: {\n        requestId: 'xjdh3j2...',  \u002F\u002F Унікальний ID запиту\n        arg: undefined             \u002F\u002F Аргумент, переданий у thunk\n    }\n}\n\n\u002F\u002F Обробка в extraReducers:\nbuilder.addCase(fetchTrips.pending, (state) => {\n    state.loading = true\n    state.error = null\n})\n","1. pending (Початок)",[3769,20997,20998,21003,21007,21018,21024,21039,21050,21054,21058,21062,21067,21094,21106,21118],{"__ignoreMap":3767},[3772,20999,21000],{"class":3774,"line":3775},[3772,21001,21002],{"class":3934},"\u002F\u002F Відправляється автоматично при виклику thunk\n",[3772,21004,21005],{"class":3774,"line":3938},[3772,21006,4714],{"class":3945},[3772,21008,21009,21011,21013,21016],{"class":3774,"line":3961},[3772,21010,4970],{"class":4719},[3772,21012,4800],{"class":3945},[3772,21014,21015],{"class":3781},"'trips\u002FfetchTrips\u002Fpending'",[3772,21017,4806],{"class":3945},[3772,21019,21020,21022],{"class":3774,"line":3968},[3772,21021,7006],{"class":4719},[3772,21023,4723],{"class":3945},[3772,21025,21026,21028,21030,21033,21036],{"class":3774,"line":3974},[3772,21027,14876],{"class":4719},[3772,21029,4800],{"class":3945},[3772,21031,21032],{"class":3781},"'xjdh3j2...'",[3772,21034,21035],{"class":3945},",  ",[3772,21037,21038],{"class":3934},"\u002F\u002F Унікальний ID запиту\n",[3772,21040,21041,21043,21045,21047],{"class":3774,"line":3996},[3772,21042,14888],{"class":4719},[3772,21044,4800],{"class":3945},[3772,21046,9862],{"class":3980},[3772,21048,21049],{"class":3934},"             \u002F\u002F Аргумент, переданий у thunk\n",[3772,21051,21052],{"class":3774,"line":4005},[3772,21053,4906],{"class":3945},[3772,21055,21056],{"class":3774,"line":4011},[3772,21057,4316],{"class":3945},[3772,21059,21060],{"class":3774,"line":4017},[3772,21061,3965],{"emptyLinePlaceholder":3964},[3772,21063,21064],{"class":3774,"line":4023},[3772,21065,21066],{"class":3934},"\u002F\u002F Обробка в extraReducers:\n",[3772,21068,21069,21071,21073,21075,21077,21080,21082,21084,21086,21088,21090,21092],{"class":3774,"line":4028},[3772,21070,9197],{"class":3949},[3772,21072,4059],{"class":3945},[3772,21074,9224],{"class":3778},[3772,21076,5150],{"class":3945},[3772,21078,21079],{"class":3949},"fetchTrips",[3772,21081,4059],{"class":3945},[3772,21083,9234],{"class":3949},[3772,21085,7128],{"class":3945},[3772,21087,5153],{"class":3949},[3772,21089,5765],{"class":3945},[3772,21091,5768],{"class":3980},[3772,21093,4002],{"class":3945},[3772,21095,21096,21098,21100,21102,21104],{"class":3774,"line":4034},[3772,21097,11256],{"class":3949},[3772,21099,4059],{"class":3945},[3772,21101,6741],{"class":3949},[3772,21103,3988],{"class":3945},[3772,21105,4865],{"class":3980},[3772,21107,21108,21110,21112,21114,21116],{"class":3774,"line":4068},[3772,21109,11256],{"class":3949},[3772,21111,4059],{"class":3945},[3772,21113,5072],{"class":3949},[3772,21115,3988],{"class":3945},[3772,21117,4816],{"class":3980},[3772,21119,21120],{"class":3774,"line":4313},[3772,21121,4020],{"class":3945},[3762,21123,21126],{"className":3925,"code":21124,"filename":21125,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Відправляється, коли payload creator повертає значення\n{\n    type: 'trips\u002FfetchTrips\u002Ffulfilled',\n    payload: [                      \u002F\u002F Результат асинхронної функції\n        { id: '1', title: 'Київ' },\n        { id: '2', title: 'Львів' }\n    ],\n    meta: {\n        requestId: 'xjdh3j2...',\n        arg: undefined\n    }\n}\n\n\u002F\u002F Обробка в extraReducers:\nbuilder.addCase(fetchTrips.fulfilled, (state, action) => {\n    state.loading = false\n    state.items = action.payload  \u002F\u002F Дані з сервера\n})\n","2. fulfilled (Успіх)",[3769,21127,21128,21133,21137,21148,21158,21175,21192,21197,21203,21213,21222,21226,21230,21234,21238,21268,21280,21299],{"__ignoreMap":3767},[3772,21129,21130],{"class":3774,"line":3775},[3772,21131,21132],{"class":3934},"\u002F\u002F Відправляється, коли payload creator повертає значення\n",[3772,21134,21135],{"class":3774,"line":3938},[3772,21136,4714],{"class":3945},[3772,21138,21139,21141,21143,21146],{"class":3774,"line":3961},[3772,21140,4970],{"class":4719},[3772,21142,4800],{"class":3945},[3772,21144,21145],{"class":3781},"'trips\u002FfetchTrips\u002Ffulfilled'",[3772,21147,4806],{"class":3945},[3772,21149,21150,21152,21155],{"class":3774,"line":3968},[3772,21151,4986],{"class":4719},[3772,21153,21154],{"class":3945},": [                      ",[3772,21156,21157],{"class":3934},"\u002F\u002F Результат асинхронної функції\n",[3772,21159,21160,21163,21165,21167,21169,21171,21173],{"class":3774,"line":3974},[3772,21161,21162],{"class":3945},"        { ",[3772,21164,4739],{"class":3949},[3772,21166,4742],{"class":3781},[3772,21168,3847],{"class":3945},[3772,21170,4747],{"class":3949},[3772,21172,10085],{"class":3781},[3772,21174,4761],{"class":3945},[3772,21176,21177,21179,21181,21183,21185,21187,21190],{"class":3774,"line":3996},[3772,21178,21162],{"class":3945},[3772,21180,4739],{"class":3949},[3772,21182,4770],{"class":3781},[3772,21184,3847],{"class":3945},[3772,21186,4747],{"class":3949},[3772,21188,21189],{"class":3781}," 'Львів'",[3772,21191,4787],{"class":3945},[3772,21193,21194],{"class":3774,"line":4005},[3772,21195,21196],{"class":3945},"    ],\n",[3772,21198,21199,21201],{"class":3774,"line":4011},[3772,21200,7006],{"class":4719},[3772,21202,4723],{"class":3945},[3772,21204,21205,21207,21209,21211],{"class":3774,"line":4017},[3772,21206,14876],{"class":4719},[3772,21208,4800],{"class":3945},[3772,21210,21032],{"class":3781},[3772,21212,4806],{"class":3945},[3772,21214,21215,21217,21219],{"class":3774,"line":4023},[3772,21216,14888],{"class":4719},[3772,21218,4800],{"class":3945},[3772,21220,21221],{"class":3980},"undefined\n",[3772,21223,21224],{"class":3774,"line":4028},[3772,21225,4906],{"class":3945},[3772,21227,21228],{"class":3774,"line":4034},[3772,21229,4316],{"class":3945},[3772,21231,21232],{"class":3774,"line":4068},[3772,21233,3965],{"emptyLinePlaceholder":3964},[3772,21235,21236],{"class":3774,"line":4313},[3772,21237,21066],{"class":3934},[3772,21239,21240,21242,21244,21246,21248,21250,21252,21254,21256,21258,21260,21262,21264,21266],{"class":3774,"line":4470},[3772,21241,9197],{"class":3949},[3772,21243,4059],{"class":3945},[3772,21245,9224],{"class":3778},[3772,21247,5150],{"class":3945},[3772,21249,21079],{"class":3949},[3772,21251,4059],{"class":3945},[3772,21253,9279],{"class":3949},[3772,21255,7128],{"class":3945},[3772,21257,5153],{"class":3949},[3772,21259,3847],{"class":3945},[3772,21261,5163],{"class":3949},[3772,21263,5765],{"class":3945},[3772,21265,5768],{"class":3980},[3772,21267,4002],{"class":3945},[3772,21269,21270,21272,21274,21276,21278],{"class":3774,"line":4879},[3772,21271,11256],{"class":3949},[3772,21273,4059],{"class":3945},[3772,21275,6741],{"class":3949},[3772,21277,3988],{"class":3945},[3772,21279,9324],{"class":3980},[3772,21281,21282,21284,21286,21288,21290,21292,21294,21296],{"class":3774,"line":4892},[3772,21283,11256],{"class":3949},[3772,21285,4059],{"class":3945},[3772,21287,5237],{"class":3949},[3772,21289,3988],{"class":3945},[3772,21291,5163],{"class":3949},[3772,21293,4059],{"class":3945},[3772,21295,5059],{"class":3949},[3772,21297,21298],{"class":3934},"  \u002F\u002F Дані з сервера\n",[3772,21300,21301],{"class":3774,"line":4903},[3772,21302,4020],{"class":3945},[3762,21304,21307],{"className":3925,"code":21305,"filename":21306,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Відправляється при помилці або rejectWithValue()\n{\n    type: 'trips\u002FfetchTrips\u002Frejected',\n    error: {\n        message: 'Network request failed',\n        name: 'Error',\n        stack: '...'\n    },\n    payload: 'Не вдалося завантажити',  \u002F\u002F Якщо використали rejectWithValue()\n    meta: {\n        requestId: 'xjdh3j2...',\n        arg: undefined,\n        aborted: false,              \u002F\u002F true, якщо викликали abort()\n        condition: false             \u002F\u002F true, якщо condition повернув false\n    }\n}\n\n\u002F\u002F Обробка в extraReducers:\nbuilder.addCase(fetchTrips.rejected, (state, action) => {\n    state.loading = false\n    state.error = action.payload ?? action.error.message\n})\n","3. rejected (Помилка)",[3769,21308,21309,21314,21318,21329,21335,21347,21359,21369,21373,21387,21393,21403,21413,21428,21439,21443,21447,21451,21455,21485,21497,21526],{"__ignoreMap":3767},[3772,21310,21311],{"class":3774,"line":3775},[3772,21312,21313],{"class":3934},"\u002F\u002F Відправляється при помилці або rejectWithValue()\n",[3772,21315,21316],{"class":3774,"line":3938},[3772,21317,4714],{"class":3945},[3772,21319,21320,21322,21324,21327],{"class":3774,"line":3961},[3772,21321,4970],{"class":4719},[3772,21323,4800],{"class":3945},[3772,21325,21326],{"class":3781},"'trips\u002FfetchTrips\u002Frejected'",[3772,21328,4806],{"class":3945},[3772,21330,21331,21333],{"class":3774,"line":3968},[3772,21332,6454],{"class":4719},[3772,21334,4723],{"class":3945},[3772,21336,21337,21340,21342,21345],{"class":3774,"line":3974},[3772,21338,21339],{"class":4719},"        message",[3772,21341,4800],{"class":3945},[3772,21343,21344],{"class":3781},"'Network request failed'",[3772,21346,4806],{"class":3945},[3772,21348,21349,21352,21354,21357],{"class":3774,"line":3996},[3772,21350,21351],{"class":4719},"        name",[3772,21353,4800],{"class":3945},[3772,21355,21356],{"class":3781},"'Error'",[3772,21358,4806],{"class":3945},[3772,21360,21361,21364,21366],{"class":3774,"line":4005},[3772,21362,21363],{"class":4719},"        stack",[3772,21365,4800],{"class":3945},[3772,21367,21368],{"class":3781},"'...'\n",[3772,21370,21371],{"class":3774,"line":4011},[3772,21372,4014],{"class":3945},[3772,21374,21375,21377,21379,21382,21384],{"class":3774,"line":4017},[3772,21376,4986],{"class":4719},[3772,21378,4800],{"class":3945},[3772,21380,21381],{"class":3781},"'Не вдалося завантажити'",[3772,21383,21035],{"class":3945},[3772,21385,21386],{"class":3934},"\u002F\u002F Якщо використали rejectWithValue()\n",[3772,21388,21389,21391],{"class":3774,"line":4023},[3772,21390,7006],{"class":4719},[3772,21392,4723],{"class":3945},[3772,21394,21395,21397,21399,21401],{"class":3774,"line":4028},[3772,21396,14876],{"class":4719},[3772,21398,4800],{"class":3945},[3772,21400,21032],{"class":3781},[3772,21402,4806],{"class":3945},[3772,21404,21405,21407,21409,21411],{"class":3774,"line":4034},[3772,21406,14888],{"class":4719},[3772,21408,4800],{"class":3945},[3772,21410,9862],{"class":3980},[3772,21412,4806],{"class":3945},[3772,21414,21415,21418,21420,21422,21425],{"class":3774,"line":4068},[3772,21416,21417],{"class":4719},"        aborted",[3772,21419,4800],{"class":3945},[3772,21421,4803],{"class":3980},[3772,21423,21424],{"class":3945},",              ",[3772,21426,21427],{"class":3934},"\u002F\u002F true, якщо викликали abort()\n",[3772,21429,21430,21432,21434,21436],{"class":3774,"line":4313},[3772,21431,20877],{"class":4719},[3772,21433,4800],{"class":3945},[3772,21435,4803],{"class":3980},[3772,21437,21438],{"class":3934},"             \u002F\u002F true, якщо condition повернув false\n",[3772,21440,21441],{"class":3774,"line":4470},[3772,21442,4906],{"class":3945},[3772,21444,21445],{"class":3774,"line":4879},[3772,21446,4316],{"class":3945},[3772,21448,21449],{"class":3774,"line":4892},[3772,21450,3965],{"emptyLinePlaceholder":3964},[3772,21452,21453],{"class":3774,"line":4903},[3772,21454,21066],{"class":3934},[3772,21456,21457,21459,21461,21463,21465,21467,21469,21471,21473,21475,21477,21479,21481,21483],{"class":3774,"line":4909},[3772,21458,9197],{"class":3949},[3772,21460,4059],{"class":3945},[3772,21462,9224],{"class":3778},[3772,21464,5150],{"class":3945},[3772,21466,21079],{"class":3949},[3772,21468,4059],{"class":3945},[3772,21470,12260],{"class":3949},[3772,21472,7128],{"class":3945},[3772,21474,5153],{"class":3949},[3772,21476,3847],{"class":3945},[3772,21478,5163],{"class":3949},[3772,21480,5765],{"class":3945},[3772,21482,5768],{"class":3980},[3772,21484,4002],{"class":3945},[3772,21486,21487,21489,21491,21493,21495],{"class":3774,"line":5521},[3772,21488,11256],{"class":3949},[3772,21490,4059],{"class":3945},[3772,21492,6741],{"class":3949},[3772,21494,3988],{"class":3945},[3772,21496,9324],{"class":3980},[3772,21498,21499,21501,21503,21505,21507,21509,21511,21513,21515,21517,21519,21521,21523],{"class":3774,"line":5527},[3772,21500,11256],{"class":3949},[3772,21502,4059],{"class":3945},[3772,21504,5072],{"class":3949},[3772,21506,3988],{"class":3945},[3772,21508,5163],{"class":3949},[3772,21510,4059],{"class":3945},[3772,21512,5059],{"class":3949},[3772,21514,12305],{"class":3945},[3772,21516,5163],{"class":3949},[3772,21518,4059],{"class":3945},[3772,21520,5072],{"class":3949},[3772,21522,4059],{"class":3945},[3772,21524,21525],{"class":3949},"message\n",[3772,21527,21528],{"class":3774,"line":5533},[3772,21529,4020],{"class":3945},[5075,21531,21532,21542,21813],{},[3743,21533,21534],{},[3829,21535,12399,21536,3869,21539,4094],{},[3769,21537,21538],{},"throw error",[3769,21540,21541],{},"rejectWithValue()",[3762,21543,21545],{"className":3925,"code":21544,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Варіант 1: Використання throw (стандартна помилка)\n;async (arg, thunkAPI) => {\n    const response = await fetch('\u002Fapi\u002Ftrips')\n    if (!response.ok) {\n        throw new Error('Не вдалося завантажити') \u002F\u002F error.message\n    }\n    return response.json()\n}\n\n\u002F\u002F У rejected дії:\n\u002F\u002F action.error.message = 'Не вдалося завантажити'\n\u002F\u002F action.payload = undefined\n\n\u002F\u002F Варіант 2: Використання rejectWithValue (кастомний payload)\n;async (arg, thunkAPI) => {\n    const response = await fetch('\u002Fapi\u002Ftrips')\n    if (!response.ok) {\n        return thunkAPI.rejectWithValue({\n            message: 'Помилка',\n            code: response.status,\n            details: await response.json(),\n        })\n    }\n    return response.json()\n}\n\n\u002F\u002F У rejected дії:\n\u002F\u002F action.payload = { message: '...', code: 404, details: {...} }\n",[3769,21546,21547,21552,21573,21591,21605,21624,21628,21640,21644,21648,21653,21658,21663,21667,21672,21692,21710,21724,21736,21746,21760,21776,21780,21784,21796,21800,21804,21808],{"__ignoreMap":3767},[3772,21548,21549],{"class":3774,"line":3775},[3772,21550,21551],{"class":3934},"\u002F\u002F Варіант 1: Використання throw (стандартна помилка)\n",[3772,21553,21554,21556,21558,21560,21563,21565,21567,21569,21571],{"class":3774,"line":3938},[3772,21555,4631],{"class":3945},[3772,21557,15084],{"class":3980},[3772,21559,5179],{"class":3945},[3772,21561,21562],{"class":3949},"arg",[3772,21564,3847],{"class":3945},[3772,21566,20629],{"class":3949},[3772,21568,5765],{"class":3945},[3772,21570,5768],{"class":3980},[3772,21572,4002],{"class":3945},[3772,21574,21575,21577,21579,21581,21583,21585,21587,21589],{"class":3774,"line":3961},[3772,21576,10944],{"class":3980},[3772,21578,15161],{"class":3984},[3772,21580,3988],{"class":3945},[3772,21582,15166],{"class":3941},[3772,21584,16769],{"class":3778},[3772,21586,5150],{"class":3945},[3772,21588,16774],{"class":3781},[3772,21590,5345],{"class":3945},[3772,21592,21593,21595,21597,21599,21601,21603],{"class":3774,"line":3968},[3772,21594,5176],{"class":3941},[3772,21596,20741],{"class":3945},[3772,21598,20744],{"class":3949},[3772,21600,4059],{"class":3945},[3772,21602,20749],{"class":3949},[3772,21604,5166],{"class":3945},[3772,21606,21607,21610,21612,21615,21617,21619,21621],{"class":3774,"line":3974},[3772,21608,21609],{"class":3941},"        throw",[3772,21611,7199],{"class":3980},[3772,21613,21614],{"class":3778}," Error",[3772,21616,5150],{"class":3945},[3772,21618,21381],{"class":3781},[3772,21620,5765],{"class":3945},[3772,21622,21623],{"class":3934},"\u002F\u002F error.message\n",[3772,21625,21626],{"class":3774,"line":3996},[3772,21627,4906],{"class":3945},[3772,21629,21630,21632,21634,21636,21638],{"class":3774,"line":4005},[3772,21631,4210],{"class":3941},[3772,21633,15161],{"class":3949},[3772,21635,4059],{"class":3945},[3772,21637,16868],{"class":3778},[3772,21639,13941],{"class":3945},[3772,21641,21642],{"class":3774,"line":4011},[3772,21643,4316],{"class":3945},[3772,21645,21646],{"class":3774,"line":4017},[3772,21647,3965],{"emptyLinePlaceholder":3964},[3772,21649,21650],{"class":3774,"line":4023},[3772,21651,21652],{"class":3934},"\u002F\u002F У rejected дії:\n",[3772,21654,21655],{"class":3774,"line":4028},[3772,21656,21657],{"class":3934},"\u002F\u002F action.error.message = 'Не вдалося завантажити'\n",[3772,21659,21660],{"class":3774,"line":4034},[3772,21661,21662],{"class":3934},"\u002F\u002F action.payload = undefined\n",[3772,21664,21665],{"class":3774,"line":4068},[3772,21666,3965],{"emptyLinePlaceholder":3964},[3772,21668,21669],{"class":3774,"line":4313},[3772,21670,21671],{"class":3934},"\u002F\u002F Варіант 2: Використання rejectWithValue (кастомний payload)\n",[3772,21673,21674,21676,21678,21680,21682,21684,21686,21688,21690],{"class":3774,"line":4470},[3772,21675,4631],{"class":3945},[3772,21677,15084],{"class":3980},[3772,21679,5179],{"class":3945},[3772,21681,21562],{"class":3949},[3772,21683,3847],{"class":3945},[3772,21685,20629],{"class":3949},[3772,21687,5765],{"class":3945},[3772,21689,5768],{"class":3980},[3772,21691,4002],{"class":3945},[3772,21693,21694,21696,21698,21700,21702,21704,21706,21708],{"class":3774,"line":4879},[3772,21695,10944],{"class":3980},[3772,21697,15161],{"class":3984},[3772,21699,3988],{"class":3945},[3772,21701,15166],{"class":3941},[3772,21703,16769],{"class":3778},[3772,21705,5150],{"class":3945},[3772,21707,16774],{"class":3781},[3772,21709,5345],{"class":3945},[3772,21711,21712,21714,21716,21718,21720,21722],{"class":3774,"line":4892},[3772,21713,5176],{"class":3941},[3772,21715,20741],{"class":3945},[3772,21717,20744],{"class":3949},[3772,21719,4059],{"class":3945},[3772,21721,20749],{"class":3949},[3772,21723,5166],{"class":3945},[3772,21725,21726,21728,21730,21732,21734],{"class":3774,"line":4903},[3772,21727,5202],{"class":3941},[3772,21729,20716],{"class":3949},[3772,21731,4059],{"class":3945},[3772,21733,15099],{"class":3778},[3772,21735,3993],{"class":3945},[3772,21737,21738,21741,21744],{"class":3774,"line":4909},[3772,21739,21740],{"class":3949},"            message:",[3772,21742,21743],{"class":3781}," 'Помилка'",[3772,21745,4806],{"class":3945},[3772,21747,21748,21751,21753,21755,21758],{"class":3774,"line":5521},[3772,21749,21750],{"class":3949},"            code:",[3772,21752,15161],{"class":3949},[3772,21754,4059],{"class":3945},[3772,21756,21757],{"class":3949},"status",[3772,21759,4806],{"class":3945},[3772,21761,21762,21765,21768,21770,21772,21774],{"class":3774,"line":5527},[3772,21763,21764],{"class":3949},"            details:",[3772,21766,21767],{"class":3941}," await",[3772,21769,15161],{"class":3949},[3772,21771,4059],{"class":3945},[3772,21773,16868],{"class":3778},[3772,21775,10241],{"class":3945},[3772,21777,21778],{"class":3774,"line":5533},[3772,21779,14303],{"class":3945},[3772,21781,21782],{"class":3774,"line":5539},[3772,21783,4906],{"class":3945},[3772,21785,21786,21788,21790,21792,21794],{"class":3774,"line":5545},[3772,21787,4210],{"class":3941},[3772,21789,15161],{"class":3949},[3772,21791,4059],{"class":3945},[3772,21793,16868],{"class":3778},[3772,21795,13941],{"class":3945},[3772,21797,21798],{"class":3774,"line":5550},[3772,21799,4316],{"class":3945},[3772,21801,21802],{"class":3774,"line":6121},[3772,21803,3965],{"emptyLinePlaceholder":3964},[3772,21805,21806],{"class":3774,"line":6131},[3772,21807,21652],{"class":3934},[3772,21809,21810],{"class":3774,"line":6136},[3772,21811,21812],{"class":3934},"\u002F\u002F action.payload = { message: '...', code: 404, details: {...} }\n",[3743,21814,21815],{},[3829,21816,9867,21817,21819],{},[3769,21818,21541],{},", коли потрібні детальні дані про помилку!",[7025,21821,21823],{"id":21822},"практичні-приклади-crud-операції-через-createasyncthunk","Практичні приклади: CRUD операції через createAsyncThunk",[3743,21825,21826],{},"Розглянемо всі основні типи HTTP-запитів з детальними поясненнями.",[9418,21828,21830],{"id":21829},"_1-get-запит-отримання-списку","1. GET запит: Отримання списку",[3762,21832,21834],{"className":3925,"code":21833,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fthunks\u002FtripsThunks.ts\nimport { createAsyncThunk } from '@reduxjs\u002Ftoolkit'\nimport { apiClient } from '@\u002Fapi\u002Fclient'\nimport type { RootState } from '..\u002Findex'\n\ninterface FetchTripsParams {\n    region?: string\n    search?: string\n    page?: number\n}\n\n\u002F**\n * GET запит з фільтрами та пагінацією\n * Використання: dispatch(fetchTripsThunk({ region: 'Захід', page: 1 }))\n *\u002F\nexport const fetchTripsThunk = createAsyncThunk\u003C\n    Trip[], \u002F\u002F Тип результату\n    FetchTripsParams, \u002F\u002F Тип параметрів (опціональні фільтри)\n    { state: RootState; rejectValue: string }\n>(\n    'trips\u002FfetchTrips',\n    async (params, { signal, rejectWithValue }) => {\n        try {\n            \u002F\u002F Будуємо query string з параметрів\n            const queryParams = new URLSearchParams()\n            if (params.region) queryParams.append('region', params.region)\n            if (params.search) queryParams.append('search', params.search)\n            if (params.page) queryParams.append('page', params.page.toString())\n\n            const response = await apiClient.get\u003CTrip[]>(\n                `\u002Ftrips?${queryParams.toString()}`,\n                { signal }, \u002F\u002F Для скасування при unmount\n            )\n\n            return response.data\n        } catch (error) {\n            if (error.name === 'AbortError') {\n                \u002F\u002F Запит було скасовано — не показуємо помилку\n                return rejectWithValue('Запит скасовано')\n            }\n            return rejectWithValue('Не вдалося завантажити поїздки')\n        }\n    },\n    {\n        \u002F\u002F Guard Condition: запобігаємо дублюванню запитів\n        condition: (params, { getState }) => {\n            const { loading } = getState().trips\n            if (loading) {\n                console.log('[Guard] Запит уже виконується')\n                return false \u002F\u002F Не запускати thunk\n            }\n            return true\n        },\n    },\n)\n",[3769,21835,21836,21841,21855,21869,21885,21889,21898,21906,21915,21924,21928,21932,21936,21941,21946,21950,21965,21975,21985,22006,22010,22016,22039,22045,22050,22067,22104,22140,22181,22185,22209,22231,22243,22247,22251,22261,22273,22292,22297,22310,22314,22327,22331,22335,22339,22344,22364,22380,22390,22405,22414,22418,22424,22428,22432],{"__ignoreMap":3767},[3772,21837,21838],{"class":3774,"line":3775},[3772,21839,21840],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fthunks\u002FtripsThunks.ts\n",[3772,21842,21843,21845,21847,21849,21851,21853],{"class":3774,"line":3938},[3772,21844,3942],{"class":3941},[3772,21846,3946],{"class":3945},[3772,21848,3853],{"class":3949},[3772,21850,3952],{"class":3945},[3772,21852,3955],{"class":3941},[3772,21854,3958],{"class":3781},[3772,21856,21857,21859,21861,21863,21865,21867],{"class":3774,"line":3961},[3772,21858,3942],{"class":3941},[3772,21860,3946],{"class":3945},[3772,21862,14944],{"class":3949},[3772,21864,3952],{"class":3945},[3772,21866,3955],{"class":3941},[3772,21868,14951],{"class":3781},[3772,21870,21871,21873,21875,21877,21879,21881,21883],{"class":3774,"line":3968},[3772,21872,3942],{"class":3941},[3772,21874,4039],{"class":3941},[3772,21876,3946],{"class":3945},[3772,21878,14962],{"class":3949},[3772,21880,3952],{"class":3945},[3772,21882,3955],{"class":3941},[3772,21884,14969],{"class":3781},[3772,21886,21887],{"class":3774,"line":3974},[3772,21888,3965],{"emptyLinePlaceholder":3964},[3772,21890,21891,21893,21896],{"class":3774,"line":3996},[3772,21892,6376],{"class":3980},[3772,21894,21895],{"class":4042}," FetchTripsParams",[3772,21897,4002],{"class":3945},[3772,21899,21900,21902,21904],{"class":3774,"line":4005},[3772,21901,6405],{"class":3949},[3772,21903,6985],{"class":3945},[3772,21905,6391],{"class":4042},[3772,21907,21908,21911,21913],{"class":3774,"line":4011},[3772,21909,21910],{"class":3949},"    search",[3772,21912,6985],{"class":3945},[3772,21914,6391],{"class":4042},[3772,21916,21917,21920,21922],{"class":3774,"line":4017},[3772,21918,21919],{"class":3949},"    page",[3772,21921,6985],{"class":3945},[3772,21923,8507],{"class":4042},[3772,21925,21926],{"class":3774,"line":4023},[3772,21927,4316],{"class":3945},[3772,21929,21930],{"class":3774,"line":4028},[3772,21931,3965],{"emptyLinePlaceholder":3964},[3772,21933,21934],{"class":3774,"line":4034},[3772,21935,17057],{"class":3934},[3772,21937,21938],{"class":3774,"line":4068},[3772,21939,21940],{"class":3934}," * GET запит з фільтрами та пагінацією\n",[3772,21942,21943],{"class":3774,"line":4313},[3772,21944,21945],{"class":3934}," * Використання: dispatch(fetchTripsThunk({ region: 'Захід', page: 1 }))\n",[3772,21947,21948],{"class":3774,"line":4470},[3772,21949,17067],{"class":3934},[3772,21951,21952,21954,21956,21959,21961,21963],{"class":3774,"line":4879},[3772,21953,3977],{"class":3941},[3772,21955,3981],{"class":3980},[3772,21957,21958],{"class":3984}," fetchTripsThunk",[3772,21960,3988],{"class":3945},[3772,21962,3853],{"class":3949},[3772,21964,14989],{"class":3945},[3772,21966,21967,21969,21972],{"class":3774,"line":4892},[3772,21968,20524],{"class":3949},[3772,21970,21971],{"class":3945},"[], ",[3772,21973,21974],{"class":3934},"\u002F\u002F Тип результату\n",[3772,21976,21977,21980,21982],{"class":3774,"line":4903},[3772,21978,21979],{"class":3949},"    FetchTripsParams",[3772,21981,3847],{"class":3945},[3772,21983,21984],{"class":3934},"\u002F\u002F Тип параметрів (опціональні фільтри)\n",[3772,21986,21987,21989,21991,21993,21995,21997,22000,22002,22004],{"class":3774,"line":4909},[3772,21988,14994],{"class":3945},[3772,21990,5153],{"class":4719},[3772,21992,4800],{"class":3945},[3772,21994,14962],{"class":3949},[3772,21996,7818],{"class":3945},[3772,21998,21999],{"class":4719},"rejectValue",[3772,22001,4800],{"class":3945},[3772,22003,6459],{"class":3949},[3772,22005,4787],{"class":3945},[3772,22007,22008],{"class":3774,"line":5521},[3772,22009,20455],{"class":3945},[3772,22011,22012,22014],{"class":3774,"line":5527},[3772,22013,20103],{"class":3781},[3772,22015,4806],{"class":3945},[3772,22017,22018,22020,22022,22025,22027,22029,22031,22033,22035,22037],{"class":3774,"line":5533},[3772,22019,16746],{"class":3980},[3772,22021,5179],{"class":3945},[3772,22023,22024],{"class":3949},"params",[3772,22026,20886],{"class":3945},[3772,22028,20721],{"class":3949},[3772,22030,3847],{"class":3945},[3772,22032,15099],{"class":3949},[3772,22034,15102],{"class":3945},[3772,22036,5768],{"class":3980},[3772,22038,4002],{"class":3945},[3772,22040,22041,22043],{"class":3774,"line":5539},[3772,22042,20679],{"class":3941},[3772,22044,4002],{"class":3945},[3772,22046,22047],{"class":3774,"line":5545},[3772,22048,22049],{"class":3934},"            \u002F\u002F Будуємо query string з параметрів\n",[3772,22051,22052,22054,22057,22059,22062,22065],{"class":3774,"line":5550},[3772,22053,8995],{"class":3980},[3772,22055,22056],{"class":3984}," queryParams",[3772,22058,3988],{"class":3945},[3772,22060,22061],{"class":3980},"new",[3772,22063,22064],{"class":3778}," URLSearchParams",[3772,22066,13941],{"class":3945},[3772,22068,22069,22071,22073,22075,22077,22079,22081,22084,22086,22089,22091,22094,22096,22098,22100,22102],{"class":3774,"line":6121},[3772,22070,9043],{"class":3941},[3772,22072,5179],{"class":3945},[3772,22074,22024],{"class":3949},[3772,22076,4059],{"class":3945},[3772,22078,7140],{"class":3949},[3772,22080,5765],{"class":3945},[3772,22082,22083],{"class":3949},"queryParams",[3772,22085,4059],{"class":3945},[3772,22087,22088],{"class":3778},"append",[3772,22090,5150],{"class":3945},[3772,22092,22093],{"class":3781},"'region'",[3772,22095,3847],{"class":3945},[3772,22097,22024],{"class":3949},[3772,22099,4059],{"class":3945},[3772,22101,7140],{"class":3949},[3772,22103,5345],{"class":3945},[3772,22105,22106,22108,22110,22112,22114,22117,22119,22121,22123,22125,22127,22130,22132,22134,22136,22138],{"class":3774,"line":6131},[3772,22107,9043],{"class":3941},[3772,22109,5179],{"class":3945},[3772,22111,22024],{"class":3949},[3772,22113,4059],{"class":3945},[3772,22115,22116],{"class":3949},"search",[3772,22118,5765],{"class":3945},[3772,22120,22083],{"class":3949},[3772,22122,4059],{"class":3945},[3772,22124,22088],{"class":3778},[3772,22126,5150],{"class":3945},[3772,22128,22129],{"class":3781},"'search'",[3772,22131,3847],{"class":3945},[3772,22133,22024],{"class":3949},[3772,22135,4059],{"class":3945},[3772,22137,22116],{"class":3949},[3772,22139,5345],{"class":3945},[3772,22141,22142,22144,22146,22148,22150,22153,22155,22157,22159,22161,22163,22166,22168,22170,22172,22174,22176,22179],{"class":3774,"line":6136},[3772,22143,9043],{"class":3941},[3772,22145,5179],{"class":3945},[3772,22147,22024],{"class":3949},[3772,22149,4059],{"class":3945},[3772,22151,22152],{"class":3949},"page",[3772,22154,5765],{"class":3945},[3772,22156,22083],{"class":3949},[3772,22158,4059],{"class":3945},[3772,22160,22088],{"class":3778},[3772,22162,5150],{"class":3945},[3772,22164,22165],{"class":3781},"'page'",[3772,22167,3847],{"class":3945},[3772,22169,22024],{"class":3949},[3772,22171,4059],{"class":3945},[3772,22173,22152],{"class":3949},[3772,22175,4059],{"class":3945},[3772,22177,22178],{"class":3778},"toString",[3772,22180,17271],{"class":3945},[3772,22182,22183],{"class":3774,"line":6142},[3772,22184,3965],{"emptyLinePlaceholder":3964},[3772,22186,22187,22189,22191,22193,22195,22197,22199,22202,22204,22206],{"class":3774,"line":6150},[3772,22188,8995],{"class":3980},[3772,22190,15161],{"class":3984},[3772,22192,3988],{"class":3945},[3772,22194,15166],{"class":3941},[3772,22196,15169],{"class":3949},[3772,22198,4059],{"class":3945},[3772,22200,22201],{"class":3778},"get",[3772,22203,4051],{"class":3945},[3772,22205,6436],{"class":4042},[3772,22207,22208],{"class":3945},"[]>(\n",[3772,22210,22211,22214,22216,22218,22220,22222,22225,22227,22229],{"class":3774,"line":6157},[3772,22212,22213],{"class":3781},"                `\u002Ftrips?",[3772,22215,15182],{"class":3980},[3772,22217,22083],{"class":3949},[3772,22219,4059],{"class":4272},[3772,22221,22178],{"class":3778},[3772,22223,22224],{"class":4272},"()",[3772,22226,4235],{"class":3980},[3772,22228,17171],{"class":3781},[3772,22230,4806],{"class":3945},[3772,22232,22233,22236,22238,22240],{"class":3774,"line":6162},[3772,22234,22235],{"class":3945},"                { ",[3772,22237,20721],{"class":3949},[3772,22239,15011],{"class":3945},[3772,22241,22242],{"class":3934},"\u002F\u002F Для скасування при unmount\n",[3772,22244,22245],{"class":3774,"line":6629},[3772,22246,13008],{"class":3945},[3772,22248,22249],{"class":3774,"line":6653},[3772,22250,3965],{"emptyLinePlaceholder":3964},[3772,22252,22253,22255,22257,22259],{"class":3774,"line":6698},[3772,22254,5977],{"class":3941},[3772,22256,15161],{"class":3949},[3772,22258,4059],{"class":3945},[3772,22260,16789],{"class":3949},[3772,22262,22263,22265,22267,22269,22271],{"class":3774,"line":6703},[3772,22264,20813],{"class":3945},[3772,22266,15259],{"class":3941},[3772,22268,5179],{"class":3945},[3772,22270,5072],{"class":3949},[3772,22272,5166],{"class":3945},[3772,22274,22275,22277,22279,22281,22283,22285,22287,22290],{"class":3774,"line":6709},[3772,22276,9043],{"class":3941},[3772,22278,5179],{"class":3945},[3772,22280,5072],{"class":3949},[3772,22282,4059],{"class":3945},[3772,22284,4838],{"class":3949},[3772,22286,5188],{"class":3945},[3772,22288,22289],{"class":3781},"'AbortError'",[3772,22291,5166],{"class":3945},[3772,22293,22294],{"class":3774,"line":6734},[3772,22295,22296],{"class":3934},"                \u002F\u002F Запит було скасовано — не показуємо помилку\n",[3772,22298,22299,22301,22303,22305,22308],{"class":3774,"line":6753},[3772,22300,8868],{"class":3941},[3772,22302,15277],{"class":3778},[3772,22304,5150],{"class":3945},[3772,22306,22307],{"class":3781},"'Запит скасовано'",[3772,22309,5345],{"class":3945},[3772,22311,22312],{"class":3774,"line":6758},[3772,22313,6016],{"class":3945},[3772,22315,22316,22318,22320,22322,22325],{"class":3774,"line":6763},[3772,22317,5977],{"class":3941},[3772,22319,15277],{"class":3778},[3772,22321,5150],{"class":3945},[3772,22323,22324],{"class":3781},"'Не вдалося завантажити поїздки'",[3772,22326,5345],{"class":3945},[3772,22328,22329],{"class":3774,"line":6768},[3772,22330,5245],{"class":3945},[3772,22332,22333],{"class":3774,"line":6773},[3772,22334,4014],{"class":3945},[3772,22336,22337],{"class":3774,"line":6779},[3772,22338,15034],{"class":3945},[3772,22340,22341],{"class":3774,"line":6812},[3772,22342,22343],{"class":3934},"        \u002F\u002F Guard Condition: запобігаємо дублюванню запитів\n",[3772,22345,22346,22348,22350,22352,22354,22356,22358,22360,22362],{"class":3774,"line":6817},[3772,22347,20877],{"class":3778},[3772,22349,4094],{"class":3949},[3772,22351,5179],{"class":3945},[3772,22353,22024],{"class":3949},[3772,22355,20886],{"class":3945},[3772,22357,4062],{"class":3949},[3772,22359,15102],{"class":3945},[3772,22361,5768],{"class":3980},[3772,22363,4002],{"class":3945},[3772,22365,22366,22368,22370,22372,22374,22376,22378],{"class":3774,"line":6823},[3772,22367,8995],{"class":3980},[3772,22369,3946],{"class":3945},[3772,22371,6741],{"class":3984},[3772,22373,6801],{"class":3945},[3772,22375,4062],{"class":3778},[3772,22377,7205],{"class":3945},[3772,22379,20911],{"class":3949},[3772,22381,22382,22384,22386,22388],{"class":3774,"line":8841},[3772,22383,9043],{"class":3941},[3772,22385,5179],{"class":3945},[3772,22387,6741],{"class":3949},[3772,22389,5166],{"class":3945},[3772,22391,22392,22394,22396,22398,22400,22403],{"class":3774,"line":8865},[3772,22393,15663],{"class":3949},[3772,22395,4059],{"class":3945},[3772,22397,7289],{"class":3778},[3772,22399,5150],{"class":3945},[3772,22401,22402],{"class":3781},"'[Guard] Запит уже виконується'",[3772,22404,5345],{"class":3945},[3772,22406,22407,22409,22411],{"class":3774,"line":8873},[3772,22408,8868],{"class":3941},[3772,22410,4279],{"class":3980},[3772,22412,22413],{"class":3934}," \u002F\u002F Не запускати thunk\n",[3772,22415,22416],{"class":3774,"line":8881},[3772,22417,6016],{"class":3945},[3772,22419,22420,22422],{"class":3774,"line":8894},[3772,22421,5977],{"class":3941},[3772,22423,20946],{"class":3980},[3772,22425,22426],{"class":3774,"line":8902},[3772,22427,6621],{"class":3945},[3772,22429,22430],{"class":3774,"line":8910},[3772,22431,4014],{"class":3945},[3772,22433,22434],{"class":3774,"line":8922},[3772,22435,5345],{"class":3945},[3875,22437,22438,22451],{},[3743,22439,22440,22443,22444,22447,22448,22450],{},[3829,22441,22442],{},"Guard Condition"," — це функція, яка виконується ",[3829,22445,22446],{},"перед"," запуском thunk. Якщо вона повертає ",[3769,22449,4803],{},", thunk не виконується взагалі. Це ідеально для:",[3833,22452,22453,22456,22459],{},[3836,22454,22455],{},"Запобігання повторним запитам",[3836,22457,22458],{},"Перевірки авторізації перед запитом",[3836,22460,22461],{},"Пропуску запиту, якщо дані вже є в кеші",[9418,22463,22465],{"id":22464},"_2-post-запит-створення-нової-сутності","2. POST запит: Створення нової сутності",[3762,22467,22469],{"className":3925,"code":22468,"language":3927,"meta":3767,"style":3767},"interface CreateTripDto {\n    title: string\n    region: string\n    startDate: string\n    description?: string\n}\n\n\u002F**\n * POST запит для створення поїздки\n * Використання: dispatch(createTripThunk({ title: 'Карпати', region: 'Захід', ... }))\n *\u002F\nexport const createTripThunk = createAsyncThunk\u003C\n    Trip, \u002F\u002F Сервер повертає створений об'єкт з ID\n    CreateTripDto, \u002F\u002F Дані для створення\n    { rejectValue: string }\n>('trips\u002FcreateTrip', async (newTripData, { rejectWithValue }) => {\n    try {\n        const response = await apiClient.post\u003CTrip>('\u002Ftrips', newTripData)\n\n        \u002F\u002F Можемо відправити аналітичну подію\n        console.log('[Analytics] Поїздку створено:', response.data.id)\n\n        return response.data\n    } catch (error) {\n        \u002F\u002F Детальна обробка помилок\n        if (error.response?.status === 400) {\n            return rejectWithValue('Некоректні дані поїздки')\n        }\n        if (error.response?.status === 401) {\n            return rejectWithValue('Потрібна авторизація')\n        }\n        return rejectWithValue('Не вдалося створити поїздку')\n    }\n})\n\n\u002F\u002F Обробка в slice:\nbuilder.addCase(createTripThunk.fulfilled, (state, action) => {\n    \u002F\u002F Оптимістичне додавання в початок списку\n    state.items.unshift(action.payload)\n    state.isCreating = false\n})\n",[3769,22470,22471,22480,22488,22496,22505,22514,22518,22522,22526,22531,22536,22540,22555,22564,22574,22586,22612,22618,22649,22653,22658,22685,22689,22699,22711,22716,22739,22752,22756,22779,22792,22796,22809,22813,22817,22821,22826,22856,22861,22883,22896],{"__ignoreMap":3767},[3772,22472,22473,22475,22478],{"class":3774,"line":3775},[3772,22474,6376],{"class":3980},[3772,22476,22477],{"class":4042}," CreateTripDto",[3772,22479,4002],{"class":3945},[3772,22481,22482,22484,22486],{"class":3774,"line":3938},[3772,22483,6396],{"class":3949},[3772,22485,4800],{"class":3945},[3772,22487,6391],{"class":4042},[3772,22489,22490,22492,22494],{"class":3774,"line":3961},[3772,22491,6405],{"class":3949},[3772,22493,4800],{"class":3945},[3772,22495,6391],{"class":4042},[3772,22497,22498,22501,22503],{"class":3774,"line":3968},[3772,22499,22500],{"class":3949},"    startDate",[3772,22502,4800],{"class":3945},[3772,22504,6391],{"class":4042},[3772,22506,22507,22510,22512],{"class":3774,"line":3974},[3772,22508,22509],{"class":3949},"    description",[3772,22511,6985],{"class":3945},[3772,22513,6391],{"class":4042},[3772,22515,22516],{"class":3774,"line":3996},[3772,22517,4316],{"class":3945},[3772,22519,22520],{"class":3774,"line":4005},[3772,22521,3965],{"emptyLinePlaceholder":3964},[3772,22523,22524],{"class":3774,"line":4011},[3772,22525,17057],{"class":3934},[3772,22527,22528],{"class":3774,"line":4017},[3772,22529,22530],{"class":3934}," * POST запит для створення поїздки\n",[3772,22532,22533],{"class":3774,"line":4023},[3772,22534,22535],{"class":3934}," * Використання: dispatch(createTripThunk({ title: 'Карпати', region: 'Захід', ... }))\n",[3772,22537,22538],{"class":3774,"line":4028},[3772,22539,17067],{"class":3934},[3772,22541,22542,22544,22546,22549,22551,22553],{"class":3774,"line":4034},[3772,22543,3977],{"class":3941},[3772,22545,3981],{"class":3980},[3772,22547,22548],{"class":3984}," createTripThunk",[3772,22550,3988],{"class":3945},[3772,22552,3853],{"class":3949},[3772,22554,14989],{"class":3945},[3772,22556,22557,22559,22561],{"class":3774,"line":4068},[3772,22558,20524],{"class":3949},[3772,22560,3847],{"class":3945},[3772,22562,22563],{"class":3934},"\u002F\u002F Сервер повертає створений об'єкт з ID\n",[3772,22565,22566,22569,22571],{"class":3774,"line":4313},[3772,22567,22568],{"class":3949},"    CreateTripDto",[3772,22570,3847],{"class":3945},[3772,22572,22573],{"class":3934},"\u002F\u002F Дані для створення\n",[3772,22575,22576,22578,22580,22582,22584],{"class":3774,"line":4470},[3772,22577,14994],{"class":3945},[3772,22579,21999],{"class":4719},[3772,22581,4800],{"class":3945},[3772,22583,6459],{"class":3949},[3772,22585,4787],{"class":3945},[3772,22587,22588,22590,22593,22595,22597,22599,22602,22604,22606,22608,22610],{"class":3774,"line":4879},[3772,22589,15076],{"class":3945},[3772,22591,22592],{"class":3781},"'trips\u002FcreateTrip'",[3772,22594,3847],{"class":3945},[3772,22596,15084],{"class":3980},[3772,22598,5179],{"class":3945},[3772,22600,22601],{"class":3949},"newTripData",[3772,22603,20886],{"class":3945},[3772,22605,15099],{"class":3949},[3772,22607,15102],{"class":3945},[3772,22609,5768],{"class":3980},[3772,22611,4002],{"class":3945},[3772,22613,22614,22616],{"class":3774,"line":4892},[3772,22615,15147],{"class":3941},[3772,22617,4002],{"class":3945},[3772,22619,22620,22622,22624,22626,22628,22630,22632,22634,22636,22638,22640,22643,22645,22647],{"class":3774,"line":4903},[3772,22621,10557],{"class":3980},[3772,22623,15161],{"class":3984},[3772,22625,3988],{"class":3945},[3772,22627,15166],{"class":3941},[3772,22629,15169],{"class":3949},[3772,22631,4059],{"class":3945},[3772,22633,15174],{"class":3778},[3772,22635,4051],{"class":3945},[3772,22637,6436],{"class":4042},[3772,22639,15076],{"class":3945},[3772,22641,22642],{"class":3781},"'\u002Ftrips'",[3772,22644,3847],{"class":3945},[3772,22646,22601],{"class":3949},[3772,22648,5345],{"class":3945},[3772,22650,22651],{"class":3774,"line":4909},[3772,22652,3965],{"emptyLinePlaceholder":3964},[3772,22654,22655],{"class":3774,"line":5521},[3772,22656,22657],{"class":3934},"        \u002F\u002F Можемо відправити аналітичну подію\n",[3772,22659,22660,22662,22664,22666,22668,22671,22673,22675,22677,22679,22681,22683],{"class":3774,"line":5527},[3772,22661,13347],{"class":3949},[3772,22663,4059],{"class":3945},[3772,22665,7289],{"class":3778},[3772,22667,5150],{"class":3945},[3772,22669,22670],{"class":3781},"'[Analytics] Поїздку створено:'",[3772,22672,3847],{"class":3945},[3772,22674,20744],{"class":3949},[3772,22676,4059],{"class":3945},[3772,22678,8198],{"class":3949},[3772,22680,4059],{"class":3945},[3772,22682,5812],{"class":3949},[3772,22684,5345],{"class":3945},[3772,22686,22687],{"class":3774,"line":5533},[3772,22688,3965],{"emptyLinePlaceholder":3964},[3772,22690,22691,22693,22695,22697],{"class":3774,"line":5539},[3772,22692,5202],{"class":3941},[3772,22694,15161],{"class":3949},[3772,22696,4059],{"class":3945},[3772,22698,16789],{"class":3949},[3772,22700,22701,22703,22705,22707,22709],{"class":3774,"line":5545},[3772,22702,15256],{"class":3945},[3772,22704,15259],{"class":3941},[3772,22706,5179],{"class":3945},[3772,22708,5072],{"class":3949},[3772,22710,5166],{"class":3945},[3772,22712,22713],{"class":3774,"line":5550},[3772,22714,22715],{"class":3934},"        \u002F\u002F Детальна обробка помилок\n",[3772,22717,22718,22720,22722,22724,22726,22728,22730,22732,22734,22737],{"class":3774,"line":6121},[3772,22719,10614],{"class":3941},[3772,22721,5179],{"class":3945},[3772,22723,5072],{"class":3949},[3772,22725,4059],{"class":3945},[3772,22727,20744],{"class":3949},[3772,22729,7898],{"class":3945},[3772,22731,21757],{"class":3949},[3772,22733,5188],{"class":3945},[3772,22735,22736],{"class":8916},"400",[3772,22738,5166],{"class":3945},[3772,22740,22741,22743,22745,22747,22750],{"class":3774,"line":6131},[3772,22742,5977],{"class":3941},[3772,22744,15277],{"class":3778},[3772,22746,5150],{"class":3945},[3772,22748,22749],{"class":3781},"'Некоректні дані поїздки'",[3772,22751,5345],{"class":3945},[3772,22753,22754],{"class":3774,"line":6136},[3772,22755,5245],{"class":3945},[3772,22757,22758,22760,22762,22764,22766,22768,22770,22772,22774,22777],{"class":3774,"line":6142},[3772,22759,10614],{"class":3941},[3772,22761,5179],{"class":3945},[3772,22763,5072],{"class":3949},[3772,22765,4059],{"class":3945},[3772,22767,20744],{"class":3949},[3772,22769,7898],{"class":3945},[3772,22771,21757],{"class":3949},[3772,22773,5188],{"class":3945},[3772,22775,22776],{"class":8916},"401",[3772,22778,5166],{"class":3945},[3772,22780,22781,22783,22785,22787,22790],{"class":3774,"line":6150},[3772,22782,5977],{"class":3941},[3772,22784,15277],{"class":3778},[3772,22786,5150],{"class":3945},[3772,22788,22789],{"class":3781},"'Потрібна авторизація'",[3772,22791,5345],{"class":3945},[3772,22793,22794],{"class":3774,"line":6157},[3772,22795,5245],{"class":3945},[3772,22797,22798,22800,22802,22804,22807],{"class":3774,"line":6162},[3772,22799,5202],{"class":3941},[3772,22801,15277],{"class":3778},[3772,22803,5150],{"class":3945},[3772,22805,22806],{"class":3781},"'Не вдалося створити поїздку'",[3772,22808,5345],{"class":3945},[3772,22810,22811],{"class":3774,"line":6629},[3772,22812,4906],{"class":3945},[3772,22814,22815],{"class":3774,"line":6653},[3772,22816,4020],{"class":3945},[3772,22818,22819],{"class":3774,"line":6698},[3772,22820,3965],{"emptyLinePlaceholder":3964},[3772,22822,22823],{"class":3774,"line":6703},[3772,22824,22825],{"class":3934},"\u002F\u002F Обробка в slice:\n",[3772,22827,22828,22830,22832,22834,22836,22838,22840,22842,22844,22846,22848,22850,22852,22854],{"class":3774,"line":6709},[3772,22829,9197],{"class":3949},[3772,22831,4059],{"class":3945},[3772,22833,9224],{"class":3778},[3772,22835,5150],{"class":3945},[3772,22837,11976],{"class":3949},[3772,22839,4059],{"class":3945},[3772,22841,9279],{"class":3949},[3772,22843,7128],{"class":3945},[3772,22845,5153],{"class":3949},[3772,22847,3847],{"class":3945},[3772,22849,5163],{"class":3949},[3772,22851,5765],{"class":3945},[3772,22853,5768],{"class":3980},[3772,22855,4002],{"class":3945},[3772,22857,22858],{"class":3774,"line":6734},[3772,22859,22860],{"class":3934},"    \u002F\u002F Оптимістичне додавання в початок списку\n",[3772,22862,22863,22865,22867,22869,22871,22873,22875,22877,22879,22881],{"class":3774,"line":6753},[3772,22864,11256],{"class":3949},[3772,22866,4059],{"class":3945},[3772,22868,5237],{"class":3949},[3772,22870,4059],{"class":3945},[3772,22872,8757],{"class":3778},[3772,22874,5150],{"class":3945},[3772,22876,5163],{"class":3949},[3772,22878,4059],{"class":3945},[3772,22880,5059],{"class":3949},[3772,22882,5345],{"class":3945},[3772,22884,22885,22887,22889,22892,22894],{"class":3774,"line":6758},[3772,22886,11256],{"class":3949},[3772,22888,4059],{"class":3945},[3772,22890,22891],{"class":3949},"isCreating",[3772,22893,3988],{"class":3945},[3772,22895,9324],{"class":3980},[3772,22897,22898],{"class":3774,"line":6763},[3772,22899,4020],{"class":3945},[9418,22901,22903],{"id":22902},"_3-patch-запит-часткове-оновлення","3. PATCH запит: Часткове оновлення",[3762,22905,22907],{"className":3925,"code":22906,"language":3927,"meta":3767,"style":3767},"interface UpdateTripDto {\n    id: string\n    changes: Partial\u003CTrip> \u002F\u002F Тільки ті поля, що змінились\n}\n\n\u002F**\n * PATCH запит для оновлення окремих полів поїздки\n * Використання: dispatch(updateTripThunk({ id: '123', changes: { title: 'Нова назва' } }))\n *\u002F\nexport const updateTripThunk = createAsyncThunk\u003C\n    Trip, \u002F\u002F Сервер повертає оновлений об'єкт\n    UpdateTripDto,\n    { state: RootState; rejectValue: string }\n>('trips\u002FupdateTrip', async ({ id, changes }, { getState, rejectWithValue }) => {\n    try {\n        \u002F\u002F Оптимістичне оновлення: зберігаємо старі дані для rollback\n        const previousTrip = getState().trips.items.find((t) => t.id === id)\n\n        const response = await apiClient.patch\u003CTrip>(`\u002Ftrips\u002F${id}`, changes)\n        return response.data\n    } catch (error) {\n        return rejectWithValue('Не вдалося оновити поїздку')\n    }\n})\n\n\u002F\u002F Обробка в slice з оптимістичним оновленням:\nbuilder\n    .addCase(updateTripThunk.pending, (state, action) => {\n        \u002F\u002F ОПТИМІСТИЧНО оновлюємо UI до відповіді сервера\n        const { id, changes } = action.meta.arg\n        const trip = state.items.find((t) => t.id === id)\n        if (trip) {\n            Object.assign(trip, changes) \u002F\u002F Immer дозволяє мутацію\n        }\n    })\n    .addCase(updateTripThunk.fulfilled, (state, action) => {\n        \u002F\u002F Фіксуємо точні дані від сервера\n        const index = state.items.findIndex((t) => t.id === action.payload.id)\n        if (index !== -1) {\n            state.items[index] = action.payload\n        }\n    })\n    .addCase(updateTripThunk.rejected, (state, action) => {\n        \u002F\u002F ROLLBACK: відкочуємо до попереднього стану\n        \u002F\u002F (потрібно зберігати previousTrip у meta)\n        state.error = action.payload ?? 'Помилка оновлення'\n    })\n",[3769,22908,22909,22918,22926,22944,22948,22952,22956,22961,22966,22970,22985,22994,23001,23021,23054,23060,23065,23108,23112,23151,23161,23173,23186,23190,23194,23198,23203,23207,23235,23240,23264,23302,23312,23333,23337,23341,23369,23374,23422,23438,23458,23462,23466,23494,23499,23504,23525],{"__ignoreMap":3767},[3772,22910,22911,22913,22916],{"class":3774,"line":3775},[3772,22912,6376],{"class":3980},[3772,22914,22915],{"class":4042}," UpdateTripDto",[3772,22917,4002],{"class":3945},[3772,22919,22920,22922,22924],{"class":3774,"line":3938},[3772,22921,6386],{"class":3949},[3772,22923,4800],{"class":3945},[3772,22925,6391],{"class":4042},[3772,22927,22928,22931,22933,22935,22937,22939,22941],{"class":3774,"line":3961},[3772,22929,22930],{"class":3949},"    changes",[3772,22932,4800],{"class":3945},[3772,22934,10545],{"class":4042},[3772,22936,4051],{"class":3945},[3772,22938,6436],{"class":4042},[3772,22940,15385],{"class":3945},[3772,22942,22943],{"class":3934},"\u002F\u002F Тільки ті поля, що змінились\n",[3772,22945,22946],{"class":3774,"line":3968},[3772,22947,4316],{"class":3945},[3772,22949,22950],{"class":3774,"line":3974},[3772,22951,3965],{"emptyLinePlaceholder":3964},[3772,22953,22954],{"class":3774,"line":3996},[3772,22955,17057],{"class":3934},[3772,22957,22958],{"class":3774,"line":4005},[3772,22959,22960],{"class":3934}," * PATCH запит для оновлення окремих полів поїздки\n",[3772,22962,22963],{"class":3774,"line":4011},[3772,22964,22965],{"class":3934}," * Використання: dispatch(updateTripThunk({ id: '123', changes: { title: 'Нова назва' } }))\n",[3772,22967,22968],{"class":3774,"line":4017},[3772,22969,17067],{"class":3934},[3772,22971,22972,22974,22976,22979,22981,22983],{"class":3774,"line":4023},[3772,22973,3977],{"class":3941},[3772,22975,3981],{"class":3980},[3772,22977,22978],{"class":3984}," updateTripThunk",[3772,22980,3988],{"class":3945},[3772,22982,3853],{"class":3949},[3772,22984,14989],{"class":3945},[3772,22986,22987,22989,22991],{"class":3774,"line":4028},[3772,22988,20524],{"class":3949},[3772,22990,3847],{"class":3945},[3772,22992,22993],{"class":3934},"\u002F\u002F Сервер повертає оновлений об'єкт\n",[3772,22995,22996,22999],{"class":3774,"line":4034},[3772,22997,22998],{"class":3949},"    UpdateTripDto",[3772,23000,4806],{"class":3945},[3772,23002,23003,23005,23007,23009,23011,23013,23015,23017,23019],{"class":3774,"line":4068},[3772,23004,14994],{"class":3945},[3772,23006,5153],{"class":4719},[3772,23008,4800],{"class":3945},[3772,23010,14962],{"class":3949},[3772,23012,7818],{"class":3945},[3772,23014,21999],{"class":4719},[3772,23016,4800],{"class":3945},[3772,23018,6459],{"class":3949},[3772,23020,4787],{"class":3945},[3772,23022,23023,23025,23028,23030,23032,23034,23036,23038,23040,23042,23044,23046,23048,23050,23052],{"class":3774,"line":4313},[3772,23024,15076],{"class":3945},[3772,23026,23027],{"class":3781},"'trips\u002FupdateTrip'",[3772,23029,3847],{"class":3945},[3772,23031,15084],{"class":3980},[3772,23033,15087],{"class":3945},[3772,23035,5812],{"class":3949},[3772,23037,3847],{"class":3945},[3772,23039,10540],{"class":3949},[3772,23041,15092],{"class":3945},[3772,23043,4062],{"class":3949},[3772,23045,3847],{"class":3945},[3772,23047,15099],{"class":3949},[3772,23049,15102],{"class":3945},[3772,23051,5768],{"class":3980},[3772,23053,4002],{"class":3945},[3772,23055,23056,23058],{"class":3774,"line":4470},[3772,23057,15147],{"class":3941},[3772,23059,4002],{"class":3945},[3772,23061,23062],{"class":3774,"line":4879},[3772,23063,23064],{"class":3934},"        \u002F\u002F Оптимістичне оновлення: зберігаємо старі дані для rollback\n",[3772,23066,23067,23069,23072,23074,23076,23078,23080,23082,23084,23086,23088,23090,23092,23094,23096,23098,23100,23102,23104,23106],{"class":3774,"line":4892},[3772,23068,10557],{"class":3980},[3772,23070,23071],{"class":3984}," previousTrip",[3772,23073,3988],{"class":3945},[3772,23075,4062],{"class":3778},[3772,23077,7205],{"class":3945},[3772,23079,7557],{"class":3949},[3772,23081,4059],{"class":3945},[3772,23083,5237],{"class":3949},[3772,23085,4059],{"class":3945},[3772,23087,7856],{"class":3778},[3772,23089,6056],{"class":3945},[3772,23091,6059],{"class":3949},[3772,23093,5765],{"class":3945},[3772,23095,5768],{"class":3980},[3772,23097,6066],{"class":3949},[3772,23099,4059],{"class":3945},[3772,23101,5812],{"class":3949},[3772,23103,5188],{"class":3945},[3772,23105,5812],{"class":3949},[3772,23107,5345],{"class":3945},[3772,23109,23110],{"class":3774,"line":4903},[3772,23111,3965],{"emptyLinePlaceholder":3964},[3772,23113,23114,23116,23118,23120,23122,23124,23126,23129,23131,23133,23135,23137,23139,23141,23143,23145,23147,23149],{"class":3774,"line":4909},[3772,23115,10557],{"class":3980},[3772,23117,15161],{"class":3984},[3772,23119,3988],{"class":3945},[3772,23121,15166],{"class":3941},[3772,23123,15169],{"class":3949},[3772,23125,4059],{"class":3945},[3772,23127,23128],{"class":3778},"patch",[3772,23130,4051],{"class":3945},[3772,23132,6436],{"class":4042},[3772,23134,15076],{"class":3945},[3772,23136,15179],{"class":3781},[3772,23138,15182],{"class":3980},[3772,23140,5812],{"class":3949},[3772,23142,4235],{"class":3980},[3772,23144,17171],{"class":3781},[3772,23146,3847],{"class":3945},[3772,23148,10540],{"class":3949},[3772,23150,5345],{"class":3945},[3772,23152,23153,23155,23157,23159],{"class":3774,"line":5521},[3772,23154,5202],{"class":3941},[3772,23156,15161],{"class":3949},[3772,23158,4059],{"class":3945},[3772,23160,16789],{"class":3949},[3772,23162,23163,23165,23167,23169,23171],{"class":3774,"line":5527},[3772,23164,15256],{"class":3945},[3772,23166,15259],{"class":3941},[3772,23168,5179],{"class":3945},[3772,23170,5072],{"class":3949},[3772,23172,5166],{"class":3945},[3772,23174,23175,23177,23179,23181,23184],{"class":3774,"line":5533},[3772,23176,5202],{"class":3941},[3772,23178,15277],{"class":3778},[3772,23180,5150],{"class":3945},[3772,23182,23183],{"class":3781},"'Не вдалося оновити поїздку'",[3772,23185,5345],{"class":3945},[3772,23187,23188],{"class":3774,"line":5539},[3772,23189,4906],{"class":3945},[3772,23191,23192],{"class":3774,"line":5545},[3772,23193,4020],{"class":3945},[3772,23195,23196],{"class":3774,"line":5550},[3772,23197,3965],{"emptyLinePlaceholder":3964},[3772,23199,23200],{"class":3774,"line":6121},[3772,23201,23202],{"class":3934},"\u002F\u002F Обробка в slice з оптимістичним оновленням:\n",[3772,23204,23205],{"class":3774,"line":6131},[3772,23206,13313],{"class":3949},[3772,23208,23209,23211,23213,23215,23217,23219,23221,23223,23225,23227,23229,23231,23233],{"class":3774,"line":6136},[3772,23210,13318],{"class":3945},[3772,23212,9224],{"class":3778},[3772,23214,5150],{"class":3945},[3772,23216,12586],{"class":3949},[3772,23218,4059],{"class":3945},[3772,23220,9234],{"class":3949},[3772,23222,7128],{"class":3945},[3772,23224,5153],{"class":3949},[3772,23226,3847],{"class":3945},[3772,23228,5163],{"class":3949},[3772,23230,5765],{"class":3945},[3772,23232,5768],{"class":3980},[3772,23234,4002],{"class":3945},[3772,23236,23237],{"class":3774,"line":6142},[3772,23238,23239],{"class":3934},"        \u002F\u002F ОПТИМІСТИЧНО оновлюємо UI до відповіді сервера\n",[3772,23241,23242,23244,23246,23248,23250,23252,23254,23256,23258,23260,23262],{"class":3774,"line":6150},[3772,23243,10557],{"class":3980},[3772,23245,3946],{"class":3945},[3772,23247,5812],{"class":3984},[3772,23249,3847],{"class":3945},[3772,23251,10540],{"class":3984},[3772,23253,6801],{"class":3945},[3772,23255,5163],{"class":3949},[3772,23257,4059],{"class":3945},[3772,23259,5067],{"class":3949},[3772,23261,4059],{"class":3945},[3772,23263,15580],{"class":3949},[3772,23265,23266,23268,23270,23272,23274,23276,23278,23280,23282,23284,23286,23288,23290,23292,23294,23296,23298,23300],{"class":3774,"line":6157},[3772,23267,10557],{"class":3980},[3772,23269,5788],{"class":3984},[3772,23271,3988],{"class":3945},[3772,23273,5153],{"class":3949},[3772,23275,4059],{"class":3945},[3772,23277,5237],{"class":3949},[3772,23279,4059],{"class":3945},[3772,23281,7856],{"class":3778},[3772,23283,6056],{"class":3945},[3772,23285,6059],{"class":3949},[3772,23287,5765],{"class":3945},[3772,23289,5768],{"class":3980},[3772,23291,6066],{"class":3949},[3772,23293,4059],{"class":3945},[3772,23295,5812],{"class":3949},[3772,23297,5188],{"class":3945},[3772,23299,5812],{"class":3949},[3772,23301,5345],{"class":3945},[3772,23303,23304,23306,23308,23310],{"class":3774,"line":6162},[3772,23305,10614],{"class":3941},[3772,23307,5179],{"class":3945},[3772,23309,5762],{"class":3949},[3772,23311,5166],{"class":3945},[3772,23313,23314,23316,23318,23320,23322,23324,23326,23328,23330],{"class":3774,"line":6629},[3772,23315,10625],{"class":3949},[3772,23317,4059],{"class":3945},[3772,23319,10630],{"class":3778},[3772,23321,5150],{"class":3945},[3772,23323,5762],{"class":3949},[3772,23325,3847],{"class":3945},[3772,23327,10540],{"class":3949},[3772,23329,5765],{"class":3945},[3772,23331,23332],{"class":3934},"\u002F\u002F Immer дозволяє мутацію\n",[3772,23334,23335],{"class":3774,"line":6653},[3772,23336,5245],{"class":3945},[3772,23338,23339],{"class":3774,"line":6698},[3772,23340,13379],{"class":3945},[3772,23342,23343,23345,23347,23349,23351,23353,23355,23357,23359,23361,23363,23365,23367],{"class":3774,"line":6703},[3772,23344,13318],{"class":3945},[3772,23346,9224],{"class":3778},[3772,23348,5150],{"class":3945},[3772,23350,12586],{"class":3949},[3772,23352,4059],{"class":3945},[3772,23354,9279],{"class":3949},[3772,23356,7128],{"class":3945},[3772,23358,5153],{"class":3949},[3772,23360,3847],{"class":3945},[3772,23362,5163],{"class":3949},[3772,23364,5765],{"class":3945},[3772,23366,5768],{"class":3980},[3772,23368,4002],{"class":3945},[3772,23370,23371],{"class":3774,"line":6709},[3772,23372,23373],{"class":3934},"        \u002F\u002F Фіксуємо точні дані від сервера\n",[3772,23375,23376,23378,23381,23383,23385,23387,23389,23391,23394,23396,23398,23400,23402,23404,23406,23408,23410,23412,23414,23416,23418,23420],{"class":3774,"line":6734},[3772,23377,10557],{"class":3980},[3772,23379,23380],{"class":3984}," index",[3772,23382,3988],{"class":3945},[3772,23384,5153],{"class":3949},[3772,23386,4059],{"class":3945},[3772,23388,5237],{"class":3949},[3772,23390,4059],{"class":3945},[3772,23392,23393],{"class":3778},"findIndex",[3772,23395,6056],{"class":3945},[3772,23397,6059],{"class":3949},[3772,23399,5765],{"class":3945},[3772,23401,5768],{"class":3980},[3772,23403,6066],{"class":3949},[3772,23405,4059],{"class":3945},[3772,23407,5812],{"class":3949},[3772,23409,5188],{"class":3945},[3772,23411,5163],{"class":3949},[3772,23413,4059],{"class":3945},[3772,23415,5059],{"class":3949},[3772,23417,4059],{"class":3945},[3772,23419,5812],{"class":3949},[3772,23421,5345],{"class":3945},[3772,23423,23424,23426,23428,23430,23433,23436],{"class":3774,"line":6753},[3772,23425,10614],{"class":3941},[3772,23427,5179],{"class":3945},[3772,23429,11059],{"class":3949},[3772,23431,23432],{"class":3945}," !== -",[3772,23434,23435],{"class":8916},"1",[3772,23437,5166],{"class":3945},[3772,23439,23440,23442,23444,23446,23448,23450,23452,23454,23456],{"class":3774,"line":6758},[3772,23441,6598],{"class":3949},[3772,23443,4059],{"class":3945},[3772,23445,5237],{"class":3949},[3772,23447,10793],{"class":3945},[3772,23449,11059],{"class":3949},[3772,23451,10798],{"class":3945},[3772,23453,5163],{"class":3949},[3772,23455,4059],{"class":3945},[3772,23457,6750],{"class":3949},[3772,23459,23460],{"class":3774,"line":6763},[3772,23461,5245],{"class":3945},[3772,23463,23464],{"class":3774,"line":6768},[3772,23465,13379],{"class":3945},[3772,23467,23468,23470,23472,23474,23476,23478,23480,23482,23484,23486,23488,23490,23492],{"class":3774,"line":6773},[3772,23469,13318],{"class":3945},[3772,23471,9224],{"class":3778},[3772,23473,5150],{"class":3945},[3772,23475,12586],{"class":3949},[3772,23477,4059],{"class":3945},[3772,23479,12260],{"class":3949},[3772,23481,7128],{"class":3945},[3772,23483,5153],{"class":3949},[3772,23485,3847],{"class":3945},[3772,23487,5163],{"class":3949},[3772,23489,5765],{"class":3945},[3772,23491,5768],{"class":3980},[3772,23493,4002],{"class":3945},[3772,23495,23496],{"class":3774,"line":6779},[3772,23497,23498],{"class":3934},"        \u002F\u002F ROLLBACK: відкочуємо до попереднього стану\n",[3772,23500,23501],{"class":3774,"line":6812},[3772,23502,23503],{"class":3934},"        \u002F\u002F (потрібно зберігати previousTrip у meta)\n",[3772,23505,23506,23508,23510,23512,23514,23516,23518,23520,23522],{"class":3774,"line":6817},[3772,23507,9935],{"class":3949},[3772,23509,4059],{"class":3945},[3772,23511,5072],{"class":3949},[3772,23513,3988],{"class":3945},[3772,23515,5163],{"class":3949},[3772,23517,4059],{"class":3945},[3772,23519,5059],{"class":3949},[3772,23521,12305],{"class":3945},[3772,23523,23524],{"class":3781},"'Помилка оновлення'\n",[3772,23526,23527],{"class":3774,"line":6823},[3772,23528,13379],{"class":3945},[9418,23530,23532],{"id":23531},"_4-delete-запит-видалення-сутності","4. DELETE запит: Видалення сутності",[3762,23534,23536],{"className":3925,"code":23535,"language":3927,"meta":3767,"style":3767},"\u002F**\n * DELETE запит для видалення поїздки\n * Використання: dispatch(deleteTripThunk('trip-id-123'))\n *\u002F\nexport const deleteTripThunk = createAsyncThunk\u003C\n    string, \u002F\u002F Повертаємо ID видаленої поїздки\n    string, \u002F\u002F Приймаємо ID для видалення\n    { rejectValue: string }\n>('trips\u002FdeleteTrip', async (tripId, { rejectWithValue }) => {\n    try {\n        await apiClient.delete(`\u002Ftrips\u002F${tripId}`)\n        return tripId \u002F\u002F Повертаємо ID для видалення зі стану\n    } catch (error) {\n        return rejectWithValue('Не вдалося видалити поїздку')\n    }\n})\n\n\u002F\u002F Обробка в slice з оптимістичним видаленням:\nbuilder\n    .addCase(deleteTripThunk.pending, (state, action) => {\n        const tripId = action.meta.arg\n        \u002F\u002F ОПТИМІСТИЧНО видаляємо зі списку\n        state.items = state.items.filter((t) => t.id !== tripId)\n    })\n    .addCase(deleteTripThunk.rejected, (state, action) => {\n        \u002F\u002F При помилці потрібно ВІДНОВИТИ поїздку\n        \u002F\u002F (для цього слід зберігати deletedTrip у meta або окремому полі)\n        state.error = action.payload ?? 'Помилка видалення'\n    })\n",[3769,23537,23538,23542,23547,23552,23556,23571,23580,23589,23601,23626,23632,23657,23666,23678,23691,23695,23699,23703,23708,23712,23740,23758,23763,23803,23807,23835,23840,23845,23866],{"__ignoreMap":3767},[3772,23539,23540],{"class":3774,"line":3775},[3772,23541,17057],{"class":3934},[3772,23543,23544],{"class":3774,"line":3938},[3772,23545,23546],{"class":3934}," * DELETE запит для видалення поїздки\n",[3772,23548,23549],{"class":3774,"line":3961},[3772,23550,23551],{"class":3934}," * Використання: dispatch(deleteTripThunk('trip-id-123'))\n",[3772,23553,23554],{"class":3774,"line":3968},[3772,23555,17067],{"class":3934},[3772,23557,23558,23560,23562,23565,23567,23569],{"class":3774,"line":3974},[3772,23559,3977],{"class":3941},[3772,23561,3981],{"class":3980},[3772,23563,23564],{"class":3984}," deleteTripThunk",[3772,23566,3988],{"class":3945},[3772,23568,3853],{"class":3949},[3772,23570,14989],{"class":3945},[3772,23572,23573,23575,23577],{"class":3774,"line":3996},[3772,23574,20536],{"class":3949},[3772,23576,3847],{"class":3945},[3772,23578,23579],{"class":3934},"\u002F\u002F Повертаємо ID видаленої поїздки\n",[3772,23581,23582,23584,23586],{"class":3774,"line":4005},[3772,23583,20536],{"class":3949},[3772,23585,3847],{"class":3945},[3772,23587,23588],{"class":3934},"\u002F\u002F Приймаємо ID для видалення\n",[3772,23590,23591,23593,23595,23597,23599],{"class":3774,"line":4011},[3772,23592,14994],{"class":3945},[3772,23594,21999],{"class":4719},[3772,23596,4800],{"class":3945},[3772,23598,6459],{"class":3949},[3772,23600,4787],{"class":3945},[3772,23602,23603,23605,23608,23610,23612,23614,23616,23618,23620,23622,23624],{"class":3774,"line":4017},[3772,23604,15076],{"class":3945},[3772,23606,23607],{"class":3781},"'trips\u002FdeleteTrip'",[3772,23609,3847],{"class":3945},[3772,23611,15084],{"class":3980},[3772,23613,5179],{"class":3945},[3772,23615,7598],{"class":3949},[3772,23617,20886],{"class":3945},[3772,23619,15099],{"class":3949},[3772,23621,15102],{"class":3945},[3772,23623,5768],{"class":3980},[3772,23625,4002],{"class":3945},[3772,23627,23628,23630],{"class":3774,"line":4023},[3772,23629,15147],{"class":3941},[3772,23631,4002],{"class":3945},[3772,23633,23634,23636,23638,23640,23643,23645,23647,23649,23651,23653,23655],{"class":3774,"line":4028},[3772,23635,17963],{"class":3941},[3772,23637,15169],{"class":3949},[3772,23639,4059],{"class":3945},[3772,23641,23642],{"class":3778},"delete",[3772,23644,5150],{"class":3945},[3772,23646,15179],{"class":3781},[3772,23648,15182],{"class":3980},[3772,23650,7598],{"class":3949},[3772,23652,4235],{"class":3980},[3772,23654,17171],{"class":3781},[3772,23656,5345],{"class":3945},[3772,23658,23659,23661,23663],{"class":3774,"line":4034},[3772,23660,5202],{"class":3941},[3772,23662,18739],{"class":3949},[3772,23664,23665],{"class":3934}," \u002F\u002F Повертаємо ID для видалення зі стану\n",[3772,23667,23668,23670,23672,23674,23676],{"class":3774,"line":4068},[3772,23669,15256],{"class":3945},[3772,23671,15259],{"class":3941},[3772,23673,5179],{"class":3945},[3772,23675,5072],{"class":3949},[3772,23677,5166],{"class":3945},[3772,23679,23680,23682,23684,23686,23689],{"class":3774,"line":4313},[3772,23681,5202],{"class":3941},[3772,23683,15277],{"class":3778},[3772,23685,5150],{"class":3945},[3772,23687,23688],{"class":3781},"'Не вдалося видалити поїздку'",[3772,23690,5345],{"class":3945},[3772,23692,23693],{"class":3774,"line":4470},[3772,23694,4906],{"class":3945},[3772,23696,23697],{"class":3774,"line":4879},[3772,23698,4020],{"class":3945},[3772,23700,23701],{"class":3774,"line":4892},[3772,23702,3965],{"emptyLinePlaceholder":3964},[3772,23704,23705],{"class":3774,"line":4903},[3772,23706,23707],{"class":3934},"\u002F\u002F Обробка в slice з оптимістичним видаленням:\n",[3772,23709,23710],{"class":3774,"line":4909},[3772,23711,13313],{"class":3949},[3772,23713,23714,23716,23718,23720,23722,23724,23726,23728,23730,23732,23734,23736,23738],{"class":3774,"line":5521},[3772,23715,13318],{"class":3945},[3772,23717,9224],{"class":3778},[3772,23719,5150],{"class":3945},[3772,23721,12581],{"class":3949},[3772,23723,4059],{"class":3945},[3772,23725,9234],{"class":3949},[3772,23727,7128],{"class":3945},[3772,23729,5153],{"class":3949},[3772,23731,3847],{"class":3945},[3772,23733,5163],{"class":3949},[3772,23735,5765],{"class":3945},[3772,23737,5768],{"class":3980},[3772,23739,4002],{"class":3945},[3772,23741,23742,23744,23746,23748,23750,23752,23754,23756],{"class":3774,"line":5527},[3772,23743,10557],{"class":3980},[3772,23745,18739],{"class":3984},[3772,23747,3988],{"class":3945},[3772,23749,5163],{"class":3949},[3772,23751,4059],{"class":3945},[3772,23753,5067],{"class":3949},[3772,23755,4059],{"class":3945},[3772,23757,15580],{"class":3949},[3772,23759,23760],{"class":3774,"line":5533},[3772,23761,23762],{"class":3934},"        \u002F\u002F ОПТИМІСТИЧНО видаляємо зі списку\n",[3772,23764,23765,23767,23769,23771,23773,23775,23777,23779,23781,23783,23785,23787,23789,23791,23793,23795,23797,23799,23801],{"class":3774,"line":5539},[3772,23766,9935],{"class":3949},[3772,23768,4059],{"class":3945},[3772,23770,5237],{"class":3949},[3772,23772,3988],{"class":3945},[3772,23774,5153],{"class":3949},[3772,23776,4059],{"class":3945},[3772,23778,5237],{"class":3949},[3772,23780,4059],{"class":3945},[3772,23782,6053],{"class":3778},[3772,23784,6056],{"class":3945},[3772,23786,6059],{"class":3949},[3772,23788,5765],{"class":3945},[3772,23790,5768],{"class":3980},[3772,23792,6066],{"class":3949},[3772,23794,4059],{"class":3945},[3772,23796,5812],{"class":3949},[3772,23798,6073],{"class":3945},[3772,23800,7598],{"class":3949},[3772,23802,5345],{"class":3945},[3772,23804,23805],{"class":3774,"line":5545},[3772,23806,13379],{"class":3945},[3772,23808,23809,23811,23813,23815,23817,23819,23821,23823,23825,23827,23829,23831,23833],{"class":3774,"line":5550},[3772,23810,13318],{"class":3945},[3772,23812,9224],{"class":3778},[3772,23814,5150],{"class":3945},[3772,23816,12581],{"class":3949},[3772,23818,4059],{"class":3945},[3772,23820,12260],{"class":3949},[3772,23822,7128],{"class":3945},[3772,23824,5153],{"class":3949},[3772,23826,3847],{"class":3945},[3772,23828,5163],{"class":3949},[3772,23830,5765],{"class":3945},[3772,23832,5768],{"class":3980},[3772,23834,4002],{"class":3945},[3772,23836,23837],{"class":3774,"line":6121},[3772,23838,23839],{"class":3934},"        \u002F\u002F При помилці потрібно ВІДНОВИТИ поїздку\n",[3772,23841,23842],{"class":3774,"line":6131},[3772,23843,23844],{"class":3934},"        \u002F\u002F (для цього слід зберігати deletedTrip у meta або окремому полі)\n",[3772,23846,23847,23849,23851,23853,23855,23857,23859,23861,23863],{"class":3774,"line":6136},[3772,23848,9935],{"class":3949},[3772,23850,4059],{"class":3945},[3772,23852,5072],{"class":3949},[3772,23854,3988],{"class":3945},[3772,23856,5163],{"class":3949},[3772,23858,4059],{"class":3945},[3772,23860,5059],{"class":3949},[3772,23862,12305],{"class":3945},[3772,23864,23865],{"class":3781},"'Помилка видалення'\n",[3772,23867,23868],{"class":3774,"line":6142},[3772,23869,13379],{"class":3945},[9418,23871,23873],{"id":23872},"_5-складний-приклад-паралельне-завантаження-з-залежностями","5. Складний приклад: Паралельне завантаження з залежностями",[3762,23875,23877],{"className":3925,"code":23876,"language":3927,"meta":3767,"style":3767},"\u002F**\n * Завантажуємо поїздку та її коментарі паралельно\n *\u002F\nexport const fetchTripWithCommentsThunk = createAsyncThunk\u003C\n    { trip: Trip; comments: Comment[] },\n    string, \u002F\u002F tripId\n    { rejectValue: string }\n>('trips\u002FfetchWithComments', async (tripId, { rejectWithValue }) => {\n    try {\n        \u002F\u002F Запускаємо два запити паралельно\n        const [tripResponse, commentsResponse] = await Promise.all([\n            apiClient.get\u003CTrip>(`\u002Ftrips\u002F${tripId}`),\n            apiClient.get\u003CComment[]>(`\u002Ftrips\u002F${tripId}\u002Fcomments`),\n        ])\n\n        return {\n            trip: tripResponse.data,\n            comments: commentsResponse.data,\n        }\n    } catch (error) {\n        return rejectWithValue('Не вдалося завантажити дані')\n    }\n})\n",[3769,23878,23879,23883,23888,23892,23907,23930,23938,23950,23975,23981,23986,24015,24042,24070,24075,24079,24085,24099,24113,24117,24129,24142,24146],{"__ignoreMap":3767},[3772,23880,23881],{"class":3774,"line":3775},[3772,23882,17057],{"class":3934},[3772,23884,23885],{"class":3774,"line":3938},[3772,23886,23887],{"class":3934}," * Завантажуємо поїздку та її коментарі паралельно\n",[3772,23889,23890],{"class":3774,"line":3961},[3772,23891,17067],{"class":3934},[3772,23893,23894,23896,23898,23901,23903,23905],{"class":3774,"line":3968},[3772,23895,3977],{"class":3941},[3772,23897,3981],{"class":3980},[3772,23899,23900],{"class":3984}," fetchTripWithCommentsThunk",[3772,23902,3988],{"class":3945},[3772,23904,3853],{"class":3949},[3772,23906,14989],{"class":3945},[3772,23908,23909,23911,23913,23915,23917,23919,23922,23924,23927],{"class":3774,"line":3974},[3772,23910,14994],{"class":3945},[3772,23912,5762],{"class":4719},[3772,23914,4800],{"class":3945},[3772,23916,6436],{"class":3949},[3772,23918,7818],{"class":3945},[3772,23920,23921],{"class":4719},"comments",[3772,23923,4800],{"class":3945},[3772,23925,23926],{"class":3949},"Comment",[3772,23928,23929],{"class":3945},"[] },\n",[3772,23931,23932,23934,23936],{"class":3774,"line":3996},[3772,23933,20536],{"class":3949},[3772,23935,3847],{"class":3945},[3772,23937,20541],{"class":3934},[3772,23939,23940,23942,23944,23946,23948],{"class":3774,"line":4005},[3772,23941,14994],{"class":3945},[3772,23943,21999],{"class":4719},[3772,23945,4800],{"class":3945},[3772,23947,6459],{"class":3949},[3772,23949,4787],{"class":3945},[3772,23951,23952,23954,23957,23959,23961,23963,23965,23967,23969,23971,23973],{"class":3774,"line":4011},[3772,23953,15076],{"class":3945},[3772,23955,23956],{"class":3781},"'trips\u002FfetchWithComments'",[3772,23958,3847],{"class":3945},[3772,23960,15084],{"class":3980},[3772,23962,5179],{"class":3945},[3772,23964,7598],{"class":3949},[3772,23966,20886],{"class":3945},[3772,23968,15099],{"class":3949},[3772,23970,15102],{"class":3945},[3772,23972,5768],{"class":3980},[3772,23974,4002],{"class":3945},[3772,23976,23977,23979],{"class":3774,"line":4017},[3772,23978,15147],{"class":3941},[3772,23980,4002],{"class":3945},[3772,23982,23983],{"class":3774,"line":4023},[3772,23984,23985],{"class":3934},"        \u002F\u002F Запускаємо два запити паралельно\n",[3772,23987,23988,23990,23992,23995,23997,24000,24002,24004,24007,24009,24012],{"class":3774,"line":4028},[3772,23989,10557],{"class":3980},[3772,23991,5221],{"class":3945},[3772,23993,23994],{"class":3984},"tripResponse",[3772,23996,3847],{"class":3945},[3772,23998,23999],{"class":3984},"commentsResponse",[3772,24001,10798],{"class":3945},[3772,24003,15166],{"class":3941},[3772,24005,24006],{"class":4042}," Promise",[3772,24008,4059],{"class":3945},[3772,24010,24011],{"class":3778},"all",[3772,24013,24014],{"class":3945},"([\n",[3772,24016,24017,24020,24022,24024,24026,24028,24030,24032,24034,24036,24038,24040],{"class":3774,"line":4034},[3772,24018,24019],{"class":3949},"            apiClient",[3772,24021,4059],{"class":3945},[3772,24023,22201],{"class":3778},[3772,24025,4051],{"class":3945},[3772,24027,6436],{"class":4042},[3772,24029,15076],{"class":3945},[3772,24031,15179],{"class":3781},[3772,24033,15182],{"class":3980},[3772,24035,7598],{"class":3949},[3772,24037,4235],{"class":3980},[3772,24039,17171],{"class":3781},[3772,24041,6082],{"class":3945},[3772,24043,24044,24046,24048,24050,24052,24054,24057,24059,24061,24063,24065,24068],{"class":3774,"line":4068},[3772,24045,24019],{"class":3949},[3772,24047,4059],{"class":3945},[3772,24049,22201],{"class":3778},[3772,24051,4051],{"class":3945},[3772,24053,23926],{"class":4042},[3772,24055,24056],{"class":3945},"[]>(",[3772,24058,15179],{"class":3781},[3772,24060,15182],{"class":3980},[3772,24062,7598],{"class":3949},[3772,24064,4235],{"class":3980},[3772,24066,24067],{"class":3781},"\u002Fcomments`",[3772,24069,6082],{"class":3945},[3772,24071,24072],{"class":3774,"line":4313},[3772,24073,24074],{"class":3945},"        ])\n",[3772,24076,24077],{"class":3774,"line":4470},[3772,24078,3965],{"emptyLinePlaceholder":3964},[3772,24080,24081,24083],{"class":3774,"line":4879},[3772,24082,5202],{"class":3941},[3772,24084,4002],{"class":3945},[3772,24086,24087,24090,24093,24095,24097],{"class":3774,"line":4892},[3772,24088,24089],{"class":3949},"            trip:",[3772,24091,24092],{"class":3949}," tripResponse",[3772,24094,4059],{"class":3945},[3772,24096,8198],{"class":3949},[3772,24098,4806],{"class":3945},[3772,24100,24101,24104,24107,24109,24111],{"class":3774,"line":4903},[3772,24102,24103],{"class":3949},"            comments:",[3772,24105,24106],{"class":3949}," commentsResponse",[3772,24108,4059],{"class":3945},[3772,24110,8198],{"class":3949},[3772,24112,4806],{"class":3945},[3772,24114,24115],{"class":3774,"line":4909},[3772,24116,5245],{"class":3945},[3772,24118,24119,24121,24123,24125,24127],{"class":3774,"line":5521},[3772,24120,15256],{"class":3945},[3772,24122,15259],{"class":3941},[3772,24124,5179],{"class":3945},[3772,24126,5072],{"class":3949},[3772,24128,5166],{"class":3945},[3772,24130,24131,24133,24135,24137,24140],{"class":3774,"line":5527},[3772,24132,5202],{"class":3941},[3772,24134,15277],{"class":3778},[3772,24136,5150],{"class":3945},[3772,24138,24139],{"class":3781},"'Не вдалося завантажити дані'",[3772,24141,5345],{"class":3945},[3772,24143,24144],{"class":3774,"line":5533},[3772,24145,4906],{"class":3945},[3772,24147,24148],{"class":3774,"line":5539},[3772,24149,4020],{"class":3945},[10844,24151,24152,24366,24509],{},[10847,24153,24155,24165,24359],{"icon":11289,"title":24154},"Як скасувати запит при unmount компонента?",[3743,24156,24157,24158,24161,24162,4094],{},"Використовуйте метод ",[3769,24159,24160],{},".abort()"," на результаті ",[3769,24163,24164],{},"dispatch()",[3762,24166,24168],{"className":4129,"code":24167,"language":4131,"meta":3767,"style":3767},"import { useEffect } from 'react'\nimport { useAppDispatch } from '@\u002Fstore\u002Fhooks'\nimport { fetchTripsThunk } from '@\u002Fstore\u002Fthunks\u002FtripsThunks'\n\nexport function TripsListScreen() {\n    const dispatch = useAppDispatch()\n\n    useEffect(() => {\n        \u002F\u002F Запускаємо thunk і зберігаємо promise\n        const promise = dispatch(fetchTripsThunk())\n\n        return () => {\n            \u002F\u002F При розмонтуванні скасовуємо запит\n            promise.abort()\n            console.log('[Cleanup] HTTP запит скасовано')\n        }\n    }, [dispatch])\n\n    return \u003CTripsList \u002F>\n}\n",[3769,24169,24170,24185,24199,24214,24218,24229,24241,24245,24257,24262,24279,24283,24293,24298,24310,24326,24330,24340,24344,24355],{"__ignoreMap":3767},[3772,24171,24172,24174,24176,24179,24181,24183],{"class":3774,"line":3775},[3772,24173,3942],{"class":3941},[3772,24175,3946],{"class":3945},[3772,24177,24178],{"class":3949},"useEffect",[3772,24180,3952],{"class":3945},[3772,24182,3955],{"class":3941},[3772,24184,14507],{"class":3781},[3772,24186,24187,24189,24191,24193,24195,24197],{"class":3774,"line":3938},[3772,24188,3942],{"class":3941},[3772,24190,3946],{"class":3945},[3772,24192,14537],{"class":3949},[3772,24194,3952],{"class":3945},[3772,24196,3955],{"class":3941},[3772,24198,14548],{"class":3781},[3772,24200,24201,24203,24205,24207,24209,24211],{"class":3774,"line":3961},[3772,24202,3942],{"class":3941},[3772,24204,3946],{"class":3945},[3772,24206,9229],{"class":3949},[3772,24208,3952],{"class":3945},[3772,24210,3955],{"class":3941},[3772,24212,24213],{"class":3781}," '@\u002Fstore\u002Fthunks\u002FtripsThunks'\n",[3772,24215,24216],{"class":3774,"line":3968},[3772,24217,3965],{"emptyLinePlaceholder":3964},[3772,24219,24220,24222,24224,24227],{"class":3774,"line":3974},[3772,24221,3977],{"class":3941},[3772,24223,4199],{"class":3980},[3772,24225,24226],{"class":3778}," TripsListScreen",[3772,24228,4205],{"class":3945},[3772,24230,24231,24233,24235,24237,24239],{"class":3774,"line":3996},[3772,24232,10944],{"class":3980},[3772,24234,14600],{"class":3984},[3772,24236,3988],{"class":3945},[3772,24238,14537],{"class":3778},[3772,24240,13941],{"class":3945},[3772,24242,24243],{"class":3774,"line":4005},[3772,24244,3965],{"emptyLinePlaceholder":3964},[3772,24246,24247,24250,24253,24255],{"class":3774,"line":4011},[3772,24248,24249],{"class":3778},"    useEffect",[3772,24251,24252],{"class":3945},"(() ",[3772,24254,5768],{"class":3980},[3772,24256,4002],{"class":3945},[3772,24258,24259],{"class":3774,"line":4017},[3772,24260,24261],{"class":3934},"        \u002F\u002F Запускаємо thunk і зберігаємо promise\n",[3772,24263,24264,24266,24269,24271,24273,24275,24277],{"class":3774,"line":4023},[3772,24265,10557],{"class":3980},[3772,24267,24268],{"class":3984}," promise",[3772,24270,3988],{"class":3945},[3772,24272,9962],{"class":3778},[3772,24274,5150],{"class":3945},[3772,24276,9229],{"class":3778},[3772,24278,17271],{"class":3945},[3772,24280,24281],{"class":3774,"line":4028},[3772,24282,3965],{"emptyLinePlaceholder":3964},[3772,24284,24285,24287,24289,24291],{"class":3774,"line":4034},[3772,24286,5202],{"class":3941},[3772,24288,16835],{"class":3945},[3772,24290,5768],{"class":3980},[3772,24292,4002],{"class":3945},[3772,24294,24295],{"class":3774,"line":4068},[3772,24296,24297],{"class":3934},"            \u002F\u002F При розмонтуванні скасовуємо запит\n",[3772,24299,24300,24303,24305,24308],{"class":3774,"line":4313},[3772,24301,24302],{"class":3949},"            promise",[3772,24304,4059],{"class":3945},[3772,24306,24307],{"class":3778},"abort",[3772,24309,13941],{"class":3945},[3772,24311,24312,24315,24317,24319,24321,24324],{"class":3774,"line":4470},[3772,24313,24314],{"class":3949},"            console",[3772,24316,4059],{"class":3945},[3772,24318,7289],{"class":3778},[3772,24320,5150],{"class":3945},[3772,24322,24323],{"class":3781},"'[Cleanup] HTTP запит скасовано'",[3772,24325,5345],{"class":3945},[3772,24327,24328],{"class":3774,"line":4879},[3772,24329,5245],{"class":3945},[3772,24331,24332,24335,24337],{"class":3774,"line":4892},[3772,24333,24334],{"class":3945},"    }, [",[3772,24336,9962],{"class":3949},[3772,24338,24339],{"class":3945},"])\n",[3772,24341,24342],{"class":3774,"line":4903},[3772,24343,3965],{"emptyLinePlaceholder":3964},[3772,24345,24346,24348,24350,24353],{"class":3774,"line":4909},[3772,24347,4210],{"class":3941},[3772,24349,16094],{"class":4218},[3772,24351,24352],{"class":4042},"TripsList",[3772,24354,4287],{"class":4218},[3772,24356,24357],{"class":3774,"line":5521},[3772,24358,4316],{"class":3945},[3743,24360,24361,24362,24365],{},"Це відправить ",[3769,24363,24364],{},"AbortSignal"," у fetch, що зупинить запит.",[10847,24367,24370,24375],{"icon":24368,"title":24369},"i-lucide-git-branch","Як обробити кілька послідовних запитів?",[3743,24371,9867,24372,24374],{},[3769,24373,9962],{}," всередині thunk:",[3762,24376,24378],{"className":3925,"code":24377,"language":3927,"meta":3767,"style":3767},"export const createTripAndFetchListThunk = createAsyncThunk\u003Cvoid, CreateTripDto, { dispatch: AppDispatch }>(\n    'trips\u002FcreateAndRefresh',\n    async (newTrip, { dispatch }) => {\n        \u002F\u002F 1. Спочатку створюємо поїздку\n        await dispatch(createTripThunk(newTrip)).unwrap()\n\n        \u002F\u002F 2. Потім перезавантажуємо список\n        await dispatch(fetchTripsThunk()).unwrap()\n\n        \u002F\u002F unwrap() викидає помилку, якщо thunk rejected\n    },\n)\n",[3769,24379,24380,24414,24421,24439,24444,24466,24470,24475,24492,24496,24501,24505],{"__ignoreMap":3767},[3772,24381,24382,24384,24386,24389,24391,24393,24395,24398,24400,24403,24405,24407,24409,24411],{"class":3774,"line":3775},[3772,24383,3977],{"class":3941},[3772,24385,3981],{"class":3980},[3772,24387,24388],{"class":3984}," createTripAndFetchListThunk",[3772,24390,3988],{"class":3945},[3772,24392,3853],{"class":3778},[3772,24394,4051],{"class":3945},[3772,24396,24397],{"class":4042},"void",[3772,24399,3847],{"class":3945},[3772,24401,24402],{"class":4042},"CreateTripDto",[3772,24404,20886],{"class":3945},[3772,24406,9962],{"class":3949},[3772,24408,4800],{"class":3945},[3772,24410,17675],{"class":4042},[3772,24412,24413],{"class":3945}," }>(\n",[3772,24415,24416,24419],{"class":3774,"line":3938},[3772,24417,24418],{"class":3781},"    'trips\u002FcreateAndRefresh'",[3772,24420,4806],{"class":3945},[3772,24422,24423,24425,24427,24429,24431,24433,24435,24437],{"class":3774,"line":3961},[3772,24424,16746],{"class":3980},[3772,24426,5179],{"class":3945},[3772,24428,10983],{"class":3949},[3772,24430,20886],{"class":3945},[3772,24432,9962],{"class":3949},[3772,24434,15102],{"class":3945},[3772,24436,5768],{"class":3980},[3772,24438,4002],{"class":3945},[3772,24440,24441],{"class":3774,"line":3968},[3772,24442,24443],{"class":3934},"        \u002F\u002F 1. Спочатку створюємо поїздку\n",[3772,24445,24446,24448,24450,24452,24454,24456,24458,24461,24464],{"class":3774,"line":3974},[3772,24447,17963],{"class":3941},[3772,24449,14600],{"class":3778},[3772,24451,5150],{"class":3945},[3772,24453,11976],{"class":3778},[3772,24455,5150],{"class":3945},[3772,24457,10983],{"class":3949},[3772,24459,24460],{"class":3945},")).",[3772,24462,24463],{"class":3778},"unwrap",[3772,24465,13941],{"class":3945},[3772,24467,24468],{"class":3774,"line":3996},[3772,24469,3965],{"emptyLinePlaceholder":3964},[3772,24471,24472],{"class":3774,"line":4005},[3772,24473,24474],{"class":3934},"        \u002F\u002F 2. Потім перезавантажуємо список\n",[3772,24476,24477,24479,24481,24483,24485,24488,24490],{"class":3774,"line":4011},[3772,24478,17963],{"class":3941},[3772,24480,14600],{"class":3778},[3772,24482,5150],{"class":3945},[3772,24484,9229],{"class":3778},[3772,24486,24487],{"class":3945},"()).",[3772,24489,24463],{"class":3778},[3772,24491,13941],{"class":3945},[3772,24493,24494],{"class":3774,"line":4017},[3772,24495,3965],{"emptyLinePlaceholder":3964},[3772,24497,24498],{"class":3774,"line":4023},[3772,24499,24500],{"class":3934},"        \u002F\u002F unwrap() викидає помилку, якщо thunk rejected\n",[3772,24502,24503],{"class":3774,"line":4028},[3772,24504,4014],{"class":3945},[3772,24506,24507],{"class":3774,"line":4034},[3772,24508,5345],{"class":3945},[10847,24510,24513,24522],{"icon":24511,"title":24512},"i-lucide-package","Як передати додаткові залежності в thunk (API client)?",[3743,24514,24515,24516,24519,24520,4094],{},"Використовуйте опцію ",[3769,24517,24518],{},"extra"," в ",[3769,24521,3850],{},[3762,24523,24525],{"className":3925,"code":24524,"language":3927,"meta":3767,"style":3767},"\u002F\u002F store\u002Findex.ts\nexport const store = configureStore({\n    reducer: rootReducer,\n    middleware: (getDefaultMiddleware) =>\n        getDefaultMiddleware({\n            thunk: {\n                extraArgument: {\n                    apiClient, \u002F\u002F HTTP клієнт\n                    analytics, \u002F\u002F Аналітика\n                    storage, \u002F\u002F Локальне сховище\n                },\n            },\n        }),\n})\n\n\u002F\u002F thunk з доступом до extra:\nexport const fetchTripsThunk = createAsyncThunk\u003CTrip[], void, { extra: { apiClient: AxiosInstance } }>(\n    'trips\u002FfetchTrips',\n    async (_, { extra }) => {\n        const response = await extra.apiClient.get('\u002Ftrips')\n        return response.data\n    },\n)\n",[3769,24526,24527,24531,24545,24553,24567,24573,24579,24586,24596,24606,24616,24620,24624,24628,24632,24636,24641,24677,24683,24702,24729,24739,24743],{"__ignoreMap":3767},[3772,24528,24529],{"class":3774,"line":3775},[3772,24530,6175],{"class":3934},[3772,24532,24533,24535,24537,24539,24541,24543],{"class":3774,"line":3938},[3772,24534,3977],{"class":3941},[3772,24536,3981],{"class":3980},[3772,24538,3985],{"class":3984},[3772,24540,3988],{"class":3945},[3772,24542,3850],{"class":3778},[3772,24544,3993],{"class":3945},[3772,24546,24547,24549,24551],{"class":3774,"line":3961},[3772,24548,3999],{"class":3949},[3772,24550,6257],{"class":3949},[3772,24552,4806],{"class":3945},[3772,24554,24555,24557,24559,24561,24563,24565],{"class":3774,"line":3968},[3772,24556,17441],{"class":3778},[3772,24558,4094],{"class":3949},[3772,24560,5179],{"class":3945},[3772,24562,17448],{"class":3949},[3772,24564,5765],{"class":3945},[3772,24566,11064],{"class":3980},[3772,24568,24569,24571],{"class":3774,"line":3974},[3772,24570,17457],{"class":3778},[3772,24572,3993],{"class":3945},[3772,24574,24575,24577],{"class":3774,"line":3996},[3772,24576,17469],{"class":3949},[3772,24578,4002],{"class":3945},[3772,24580,24581,24584],{"class":3774,"line":4005},[3772,24582,24583],{"class":3949},"                extraArgument:",[3772,24585,4002],{"class":3945},[3772,24587,24588,24591,24593],{"class":3774,"line":4011},[3772,24589,24590],{"class":3949},"                    apiClient",[3772,24592,3847],{"class":3945},[3772,24594,24595],{"class":3934},"\u002F\u002F HTTP клієнт\n",[3772,24597,24598,24601,24603],{"class":3774,"line":4017},[3772,24599,24600],{"class":3949},"                    analytics",[3772,24602,3847],{"class":3945},[3772,24604,24605],{"class":3934},"\u002F\u002F Аналітика\n",[3772,24607,24608,24611,24613],{"class":3774,"line":4023},[3772,24609,24610],{"class":3949},"                    storage",[3772,24612,3847],{"class":3945},[3772,24614,24615],{"class":3934},"\u002F\u002F Локальне сховище\n",[3772,24617,24618],{"class":3774,"line":4028},[3772,24619,13003],{"class":3945},[3772,24621,24622],{"class":3774,"line":4034},[3772,24623,8838],{"class":3945},[3772,24625,24626],{"class":3774,"line":4068},[3772,24627,19177],{"class":3945},[3772,24629,24630],{"class":3774,"line":4313},[3772,24631,4020],{"class":3945},[3772,24633,24634],{"class":3774,"line":4470},[3772,24635,3965],{"emptyLinePlaceholder":3964},[3772,24637,24638],{"class":3774,"line":4879},[3772,24639,24640],{"class":3934},"\u002F\u002F thunk з доступом до extra:\n",[3772,24642,24643,24645,24647,24649,24651,24653,24655,24657,24659,24661,24663,24665,24667,24669,24671,24674],{"class":3774,"line":4892},[3772,24644,3977],{"class":3941},[3772,24646,3981],{"class":3980},[3772,24648,21958],{"class":3984},[3772,24650,3988],{"class":3945},[3772,24652,3853],{"class":3778},[3772,24654,4051],{"class":3945},[3772,24656,6436],{"class":4042},[3772,24658,21971],{"class":3945},[3772,24660,24397],{"class":4042},[3772,24662,20886],{"class":3945},[3772,24664,24518],{"class":3949},[3772,24666,4835],{"class":3945},[3772,24668,14944],{"class":3949},[3772,24670,4800],{"class":3945},[3772,24672,24673],{"class":4042},"AxiosInstance",[3772,24675,24676],{"class":3945}," } }>(\n",[3772,24678,24679,24681],{"class":3774,"line":4903},[3772,24680,20103],{"class":3781},[3772,24682,4806],{"class":3945},[3772,24684,24685,24687,24689,24692,24694,24696,24698,24700],{"class":3774,"line":4909},[3772,24686,16746],{"class":3980},[3772,24688,5179],{"class":3945},[3772,24690,24691],{"class":3949},"_",[3772,24693,20886],{"class":3945},[3772,24695,24518],{"class":3949},[3772,24697,15102],{"class":3945},[3772,24699,5768],{"class":3980},[3772,24701,4002],{"class":3945},[3772,24703,24704,24706,24708,24710,24712,24715,24717,24719,24721,24723,24725,24727],{"class":3774,"line":5521},[3772,24705,10557],{"class":3980},[3772,24707,15161],{"class":3984},[3772,24709,3988],{"class":3945},[3772,24711,15166],{"class":3941},[3772,24713,24714],{"class":3949}," extra",[3772,24716,4059],{"class":3945},[3772,24718,14944],{"class":3949},[3772,24720,4059],{"class":3945},[3772,24722,22201],{"class":3778},[3772,24724,5150],{"class":3945},[3772,24726,22642],{"class":3781},[3772,24728,5345],{"class":3945},[3772,24730,24731,24733,24735,24737],{"class":3774,"line":5527},[3772,24732,5202],{"class":3941},[3772,24734,15161],{"class":3949},[3772,24736,4059],{"class":3945},[3772,24738,16789],{"class":3949},[3772,24740,24741],{"class":3774,"line":5533},[3772,24742,4014],{"class":3945},[3772,24744,24745],{"class":3774,"line":5539},[3772,24746,5345],{"class":3945},[3762,24748,24750],{"className":3925,"code":24749,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fthunks\u002FtripsThunks.ts\nimport { createAsyncThunk } from '@reduxjs\u002Ftoolkit'\nimport { apiClient } from '@\u002Fapi\u002Fclient'\nimport { AppError } from '@\u002Fapi\u002FAppError'\nimport type { RootState, AppDispatch } from '..\u002Findex'\nimport type { Trip, CreateTripDto } from '@\u002Ffeatures\u002Ftrips\u002Ftypes'\n\n\u002F**\n * 1. GET: Завантаження списку поїздок з підтримкою AbortController та Guard Condition\n *\u002F\nexport const fetchTripsThunk = createAsyncThunk\u003C\n    Trip[], \u002F\u002F Тип успішного результату (Returned)\n    void, \u002F\u002F Вхідний аргумент (ThunkArg)\n    {\n        state: RootState\n        dispatch: AppDispatch\n        rejectValue: string\n    }\n>(\n    'trips\u002FfetchTrips',\n    async (_, { rejectWithValue, signal }) => {\n        try {\n            \u002F\u002F Передаємо signal для скасування запиту при unmount екрана\n            const response = await apiClient.get\u003CTrip[]>('\u002Ftrips', { signal })\n            return response.data\n        } catch (error) {\n            const appError = AppError.from(error)\n            return rejectWithValue(appError.userMessage)\n        }\n    },\n    {\n        \u002F\u002F Guard Condition: запобігаємо повторному запиту, якщо завантаження вже триває\n        condition: (_, { getState }) => {\n            const { loading } = getState().trips\n            if (loading) {\n                console.log('[Thunk Guard] Запит уже виконується, скасування дубліката.')\n                return false\n            }\n            return true\n        },\n    },\n)\n\n\u002F**\n * 2. POST: Створення нової поїздки з передачею payload\n *\u002F\nexport const createTripThunk = createAsyncThunk\u003C\n    Trip,\n    CreateTripDto,\n    {\n        state: RootState\n        rejectValue: string\n    }\n>('trips\u002FcreateTrip', async (newTripDto, { rejectWithValue }) => {\n    try {\n        const response = await apiClient.post\u003CTrip>('\u002Ftrips', newTripDto)\n        return response.data\n    } catch (error) {\n        const appError = AppError.from(error)\n        return rejectWithValue(appError.userMessage)\n    }\n})\n",[3769,24751,24752,24756,24770,24784,24800,24820,24841,24845,24849,24854,24858,24872,24881,24891,24895,24903,24912,24920,24924,24928,24934,24956,24962,24967,24998,25008,25020,25041,25059,25063,25067,25071,25076,25096,25112,25122,25137,25144,25148,25154,25158,25162,25166,25170,25174,25179,25183,25197,25203,25209,25213,25221,25229,25233,25258,25264,25294,25304,25316,25336,25352,25356],{"__ignoreMap":3767},[3772,24753,24754],{"class":3774,"line":3775},[3772,24755,21840],{"class":3934},[3772,24757,24758,24760,24762,24764,24766,24768],{"class":3774,"line":3938},[3772,24759,3942],{"class":3941},[3772,24761,3946],{"class":3945},[3772,24763,3853],{"class":3949},[3772,24765,3952],{"class":3945},[3772,24767,3955],{"class":3941},[3772,24769,3958],{"class":3781},[3772,24771,24772,24774,24776,24778,24780,24782],{"class":3774,"line":3961},[3772,24773,3942],{"class":3941},[3772,24775,3946],{"class":3945},[3772,24777,14944],{"class":3949},[3772,24779,3952],{"class":3945},[3772,24781,3955],{"class":3941},[3772,24783,14951],{"class":3781},[3772,24785,24786,24788,24790,24793,24795,24797],{"class":3774,"line":3968},[3772,24787,3942],{"class":3941},[3772,24789,3946],{"class":3945},[3772,24791,24792],{"class":3949},"AppError",[3772,24794,3952],{"class":3945},[3772,24796,3955],{"class":3941},[3772,24798,24799],{"class":3781}," '@\u002Fapi\u002FAppError'\n",[3772,24801,24802,24804,24806,24808,24810,24812,24814,24816,24818],{"class":3774,"line":3974},[3772,24803,3942],{"class":3941},[3772,24805,4039],{"class":3941},[3772,24807,3946],{"class":3945},[3772,24809,14962],{"class":3949},[3772,24811,3847],{"class":3945},[3772,24813,17675],{"class":3949},[3772,24815,3952],{"class":3945},[3772,24817,3955],{"class":3941},[3772,24819,14969],{"class":3781},[3772,24821,24822,24824,24826,24828,24830,24832,24834,24836,24838],{"class":3774,"line":3996},[3772,24823,3942],{"class":3941},[3772,24825,4039],{"class":3941},[3772,24827,3946],{"class":3945},[3772,24829,6436],{"class":3949},[3772,24831,3847],{"class":3945},[3772,24833,24402],{"class":3949},[3772,24835,3952],{"class":3945},[3772,24837,3955],{"class":3941},[3772,24839,24840],{"class":3781}," '@\u002Ffeatures\u002Ftrips\u002Ftypes'\n",[3772,24842,24843],{"class":3774,"line":4005},[3772,24844,3965],{"emptyLinePlaceholder":3964},[3772,24846,24847],{"class":3774,"line":4011},[3772,24848,17057],{"class":3934},[3772,24850,24851],{"class":3774,"line":4017},[3772,24852,24853],{"class":3934}," * 1. GET: Завантаження списку поїздок з підтримкою AbortController та Guard Condition\n",[3772,24855,24856],{"class":3774,"line":4023},[3772,24857,17067],{"class":3934},[3772,24859,24860,24862,24864,24866,24868,24870],{"class":3774,"line":4028},[3772,24861,3977],{"class":3941},[3772,24863,3981],{"class":3980},[3772,24865,21958],{"class":3984},[3772,24867,3988],{"class":3945},[3772,24869,3853],{"class":3949},[3772,24871,14989],{"class":3945},[3772,24873,24874,24876,24878],{"class":3774,"line":4034},[3772,24875,20524],{"class":3949},[3772,24877,21971],{"class":3945},[3772,24879,24880],{"class":3934},"\u002F\u002F Тип успішного результату (Returned)\n",[3772,24882,24883,24886,24888],{"class":3774,"line":4068},[3772,24884,24885],{"class":3980},"    void",[3772,24887,3847],{"class":3945},[3772,24889,24890],{"class":3934},"\u002F\u002F Вхідний аргумент (ThunkArg)\n",[3772,24892,24893],{"class":3774,"line":4313},[3772,24894,15034],{"class":3945},[3772,24896,24897,24899,24901],{"class":3774,"line":4470},[3772,24898,9935],{"class":4719},[3772,24900,4800],{"class":3945},[3772,24902,15043],{"class":3949},[3772,24904,24905,24907,24909],{"class":3774,"line":4879},[3772,24906,14715],{"class":4719},[3772,24908,4800],{"class":3945},[3772,24910,24911],{"class":3949},"AppDispatch\n",[3772,24913,24914,24916,24918],{"class":3774,"line":4892},[3772,24915,15048],{"class":4719},[3772,24917,4800],{"class":3945},[3772,24919,6391],{"class":3949},[3772,24921,24922],{"class":3774,"line":4903},[3772,24923,4906],{"class":3945},[3772,24925,24926],{"class":3774,"line":4909},[3772,24927,20455],{"class":3945},[3772,24929,24930,24932],{"class":3774,"line":5521},[3772,24931,20103],{"class":3781},[3772,24933,4806],{"class":3945},[3772,24935,24936,24938,24940,24942,24944,24946,24948,24950,24952,24954],{"class":3774,"line":5527},[3772,24937,16746],{"class":3980},[3772,24939,5179],{"class":3945},[3772,24941,24691],{"class":3949},[3772,24943,20886],{"class":3945},[3772,24945,15099],{"class":3949},[3772,24947,3847],{"class":3945},[3772,24949,20721],{"class":3949},[3772,24951,15102],{"class":3945},[3772,24953,5768],{"class":3980},[3772,24955,4002],{"class":3945},[3772,24957,24958,24960],{"class":3774,"line":5533},[3772,24959,20679],{"class":3941},[3772,24961,4002],{"class":3945},[3772,24963,24964],{"class":3774,"line":5539},[3772,24965,24966],{"class":3934},"            \u002F\u002F Передаємо signal для скасування запиту при unmount екрана\n",[3772,24968,24969,24971,24973,24975,24977,24979,24981,24983,24985,24987,24989,24991,24993,24995],{"class":3774,"line":5545},[3772,24970,8995],{"class":3980},[3772,24972,15161],{"class":3984},[3772,24974,3988],{"class":3945},[3772,24976,15166],{"class":3941},[3772,24978,15169],{"class":3949},[3772,24980,4059],{"class":3945},[3772,24982,22201],{"class":3778},[3772,24984,4051],{"class":3945},[3772,24986,6436],{"class":4042},[3772,24988,24056],{"class":3945},[3772,24990,22642],{"class":3781},[3772,24992,20886],{"class":3945},[3772,24994,20721],{"class":3949},[3772,24996,24997],{"class":3945}," })\n",[3772,24999,25000,25002,25004,25006],{"class":3774,"line":5550},[3772,25001,5977],{"class":3941},[3772,25003,15161],{"class":3949},[3772,25005,4059],{"class":3945},[3772,25007,16789],{"class":3949},[3772,25009,25010,25012,25014,25016,25018],{"class":3774,"line":6121},[3772,25011,20813],{"class":3945},[3772,25013,15259],{"class":3941},[3772,25015,5179],{"class":3945},[3772,25017,5072],{"class":3949},[3772,25019,5166],{"class":3945},[3772,25021,25022,25024,25027,25029,25031,25033,25035,25037,25039],{"class":3774,"line":6131},[3772,25023,8995],{"class":3980},[3772,25025,25026],{"class":3984}," appError",[3772,25028,3988],{"class":3945},[3772,25030,24792],{"class":3949},[3772,25032,4059],{"class":3945},[3772,25034,3955],{"class":3778},[3772,25036,5150],{"class":3945},[3772,25038,5072],{"class":3949},[3772,25040,5345],{"class":3945},[3772,25042,25043,25045,25047,25049,25052,25054,25057],{"class":3774,"line":6136},[3772,25044,5977],{"class":3941},[3772,25046,15277],{"class":3778},[3772,25048,5150],{"class":3945},[3772,25050,25051],{"class":3949},"appError",[3772,25053,4059],{"class":3945},[3772,25055,25056],{"class":3949},"userMessage",[3772,25058,5345],{"class":3945},[3772,25060,25061],{"class":3774,"line":6142},[3772,25062,5245],{"class":3945},[3772,25064,25065],{"class":3774,"line":6150},[3772,25066,4014],{"class":3945},[3772,25068,25069],{"class":3774,"line":6157},[3772,25070,15034],{"class":3945},[3772,25072,25073],{"class":3774,"line":6162},[3772,25074,25075],{"class":3934},"        \u002F\u002F Guard Condition: запобігаємо повторному запиту, якщо завантаження вже триває\n",[3772,25077,25078,25080,25082,25084,25086,25088,25090,25092,25094],{"class":3774,"line":6629},[3772,25079,20877],{"class":3778},[3772,25081,4094],{"class":3949},[3772,25083,5179],{"class":3945},[3772,25085,24691],{"class":3949},[3772,25087,20886],{"class":3945},[3772,25089,4062],{"class":3949},[3772,25091,15102],{"class":3945},[3772,25093,5768],{"class":3980},[3772,25095,4002],{"class":3945},[3772,25097,25098,25100,25102,25104,25106,25108,25110],{"class":3774,"line":6653},[3772,25099,8995],{"class":3980},[3772,25101,3946],{"class":3945},[3772,25103,6741],{"class":3984},[3772,25105,6801],{"class":3945},[3772,25107,4062],{"class":3778},[3772,25109,7205],{"class":3945},[3772,25111,20911],{"class":3949},[3772,25113,25114,25116,25118,25120],{"class":3774,"line":6698},[3772,25115,9043],{"class":3941},[3772,25117,5179],{"class":3945},[3772,25119,6741],{"class":3949},[3772,25121,5166],{"class":3945},[3772,25123,25124,25126,25128,25130,25132,25135],{"class":3774,"line":6703},[3772,25125,15663],{"class":3949},[3772,25127,4059],{"class":3945},[3772,25129,7289],{"class":3778},[3772,25131,5150],{"class":3945},[3772,25133,25134],{"class":3781},"'[Thunk Guard] Запит уже виконується, скасування дубліката.'",[3772,25136,5345],{"class":3945},[3772,25138,25139,25141],{"class":3774,"line":6709},[3772,25140,8868],{"class":3941},[3772,25142,25143],{"class":3980}," false\n",[3772,25145,25146],{"class":3774,"line":6734},[3772,25147,6016],{"class":3945},[3772,25149,25150,25152],{"class":3774,"line":6753},[3772,25151,5977],{"class":3941},[3772,25153,20946],{"class":3980},[3772,25155,25156],{"class":3774,"line":6758},[3772,25157,6621],{"class":3945},[3772,25159,25160],{"class":3774,"line":6763},[3772,25161,4014],{"class":3945},[3772,25163,25164],{"class":3774,"line":6768},[3772,25165,5345],{"class":3945},[3772,25167,25168],{"class":3774,"line":6773},[3772,25169,3965],{"emptyLinePlaceholder":3964},[3772,25171,25172],{"class":3774,"line":6779},[3772,25173,17057],{"class":3934},[3772,25175,25176],{"class":3774,"line":6812},[3772,25177,25178],{"class":3934}," * 2. POST: Створення нової поїздки з передачею payload\n",[3772,25180,25181],{"class":3774,"line":6817},[3772,25182,17067],{"class":3934},[3772,25184,25185,25187,25189,25191,25193,25195],{"class":3774,"line":6823},[3772,25186,3977],{"class":3941},[3772,25188,3981],{"class":3980},[3772,25190,22548],{"class":3984},[3772,25192,3988],{"class":3945},[3772,25194,3853],{"class":3949},[3772,25196,14989],{"class":3945},[3772,25198,25199,25201],{"class":3774,"line":8841},[3772,25200,20524],{"class":3949},[3772,25202,4806],{"class":3945},[3772,25204,25205,25207],{"class":3774,"line":8865},[3772,25206,22568],{"class":3949},[3772,25208,4806],{"class":3945},[3772,25210,25211],{"class":3774,"line":8873},[3772,25212,15034],{"class":3945},[3772,25214,25215,25217,25219],{"class":3774,"line":8881},[3772,25216,9935],{"class":4719},[3772,25218,4800],{"class":3945},[3772,25220,15043],{"class":3949},[3772,25222,25223,25225,25227],{"class":3774,"line":8894},[3772,25224,15048],{"class":4719},[3772,25226,4800],{"class":3945},[3772,25228,6391],{"class":3949},[3772,25230,25231],{"class":3774,"line":8902},[3772,25232,4906],{"class":3945},[3772,25234,25235,25237,25239,25241,25243,25245,25248,25250,25252,25254,25256],{"class":3774,"line":8910},[3772,25236,15076],{"class":3945},[3772,25238,22592],{"class":3781},[3772,25240,3847],{"class":3945},[3772,25242,15084],{"class":3980},[3772,25244,5179],{"class":3945},[3772,25246,25247],{"class":3949},"newTripDto",[3772,25249,20886],{"class":3945},[3772,25251,15099],{"class":3949},[3772,25253,15102],{"class":3945},[3772,25255,5768],{"class":3980},[3772,25257,4002],{"class":3945},[3772,25259,25260,25262],{"class":3774,"line":8922},[3772,25261,15147],{"class":3941},[3772,25263,4002],{"class":3945},[3772,25265,25266,25268,25270,25272,25274,25276,25278,25280,25282,25284,25286,25288,25290,25292],{"class":3774,"line":8928},[3772,25267,10557],{"class":3980},[3772,25269,15161],{"class":3984},[3772,25271,3988],{"class":3945},[3772,25273,15166],{"class":3941},[3772,25275,15169],{"class":3949},[3772,25277,4059],{"class":3945},[3772,25279,15174],{"class":3778},[3772,25281,4051],{"class":3945},[3772,25283,6436],{"class":4042},[3772,25285,15076],{"class":3945},[3772,25287,22642],{"class":3781},[3772,25289,3847],{"class":3945},[3772,25291,25247],{"class":3949},[3772,25293,5345],{"class":3945},[3772,25295,25296,25298,25300,25302],{"class":3774,"line":8934},[3772,25297,5202],{"class":3941},[3772,25299,15161],{"class":3949},[3772,25301,4059],{"class":3945},[3772,25303,16789],{"class":3949},[3772,25305,25306,25308,25310,25312,25314],{"class":3774,"line":8939},[3772,25307,15256],{"class":3945},[3772,25309,15259],{"class":3941},[3772,25311,5179],{"class":3945},[3772,25313,5072],{"class":3949},[3772,25315,5166],{"class":3945},[3772,25317,25318,25320,25322,25324,25326,25328,25330,25332,25334],{"class":3774,"line":8944},[3772,25319,10557],{"class":3980},[3772,25321,25026],{"class":3984},[3772,25323,3988],{"class":3945},[3772,25325,24792],{"class":3949},[3772,25327,4059],{"class":3945},[3772,25329,3955],{"class":3778},[3772,25331,5150],{"class":3945},[3772,25333,5072],{"class":3949},[3772,25335,5345],{"class":3945},[3772,25337,25338,25340,25342,25344,25346,25348,25350],{"class":3774,"line":8949},[3772,25339,5202],{"class":3941},[3772,25341,15277],{"class":3778},[3772,25343,5150],{"class":3945},[3772,25345,25051],{"class":3949},[3772,25347,4059],{"class":3945},[3772,25349,25056],{"class":3949},[3772,25351,5345],{"class":3945},[3772,25353,25354],{"class":3774,"line":8955},[3772,25355,4906],{"class":3945},[3772,25357,25358],{"class":3774,"line":8992},[3772,25359,4020],{"class":3945},[7025,25361,25363,25364],{"id":25362},"обробка-в-slice-через-extrareducers","Обробка в Slice через ",[3769,25365,8393],{},[3762,25367,25369],{"className":3925,"code":25368,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FtripsSlice.ts\nimport { createSlice } from '@reduxjs\u002Ftoolkit'\nimport { fetchTripsThunk, createTripThunk } from '..\u002Fthunks\u002FtripsThunks'\nimport type { Trip } from '@\u002Ffeatures\u002Ftrips\u002Ftypes'\n\ninterface TripsState {\n    items: Trip[]\n    loading: boolean\n    isCreating: boolean\n    error: string | null\n}\n\nconst initialState: TripsState = {\n    items: [],\n    loading: false,\n    isCreating: false,\n    error: null,\n}\n\nexport const tripsSlice = createSlice({\n    name: 'trips',\n    initialState,\n    reducers: {\n        clearError(state) {\n            state.error = null\n        },\n    },\n    extraReducers: (builder) => {\n        builder\n            \u002F\u002F Обробка GET fetchTrips\n            .addCase(fetchTripsThunk.pending, (state) => {\n                state.loading = true\n                state.error = null\n            })\n            .addCase(fetchTripsThunk.fulfilled, (state, action) => {\n                state.loading = false\n                state.items = action.payload\n            })\n            .addCase(fetchTripsThunk.rejected, (state, action) => {\n                state.loading = false\n                state.error = action.payload ?? 'Не вдалося завантажити поїздки'\n            })\n\n            \u002F\u002F Обробка POST createTrip\n            .addCase(createTripThunk.pending, (state) => {\n                state.isCreating = true\n                state.error = null\n            })\n            .addCase(createTripThunk.fulfilled, (state, action) => {\n                state.isCreating = false\n                state.items.unshift(action.payload)\n            })\n            .addCase(createTripThunk.rejected, (state, action) => {\n                state.isCreating = false\n                state.error = action.payload ?? 'Не вдалося створити поїздку'\n            })\n    },\n})\n",[3769,25370,25371,25375,25389,25407,25423,25427,25435,25445,25453,25462,25474,25478,25482,25494,25500,25508,25517,25525,25529,25533,25547,25555,25561,25567,25578,25590,25594,25598,25614,25618,25623,25647,25659,25671,25675,25703,25715,25731,25735,25763,25775,25796,25800,25804,25809,25833,25845,25857,25861,25889,25901,25923,25927,25955,25967,25988,25992,25996],{"__ignoreMap":3767},[3772,25372,25373],{"class":3774,"line":3775},[3772,25374,6348],{"class":3934},[3772,25376,25377,25379,25381,25383,25385,25387],{"class":3774,"line":3938},[3772,25378,3942],{"class":3941},[3772,25380,3946],{"class":3945},[3772,25382,3846],{"class":3949},[3772,25384,3952],{"class":3945},[3772,25386,3955],{"class":3941},[3772,25388,3958],{"class":3781},[3772,25390,25391,25393,25395,25397,25399,25401,25403,25405],{"class":3774,"line":3961},[3772,25392,3942],{"class":3941},[3772,25394,3946],{"class":3945},[3772,25396,9229],{"class":3949},[3772,25398,3847],{"class":3945},[3772,25400,11976],{"class":3949},[3772,25402,3952],{"class":3945},[3772,25404,3955],{"class":3941},[3772,25406,11983],{"class":3781},[3772,25408,25409,25411,25413,25415,25417,25419,25421],{"class":3774,"line":3968},[3772,25410,3942],{"class":3941},[3772,25412,4039],{"class":3941},[3772,25414,3946],{"class":3945},[3772,25416,6436],{"class":3949},[3772,25418,3952],{"class":3945},[3772,25420,3955],{"class":3941},[3772,25422,24840],{"class":3781},[3772,25424,25425],{"class":3774,"line":3974},[3772,25426,3965],{"emptyLinePlaceholder":3964},[3772,25428,25429,25431,25433],{"class":3774,"line":3996},[3772,25430,6376],{"class":3980},[3772,25432,6424],{"class":4042},[3772,25434,4002],{"class":3945},[3772,25436,25437,25439,25441,25443],{"class":3774,"line":4005},[3772,25438,6431],{"class":3949},[3772,25440,4800],{"class":3945},[3772,25442,6436],{"class":4042},[3772,25444,6439],{"class":3945},[3772,25446,25447,25449,25451],{"class":3774,"line":4011},[3772,25448,6444],{"class":3949},[3772,25450,4800],{"class":3945},[3772,25452,6449],{"class":4042},[3772,25454,25455,25458,25460],{"class":3774,"line":4017},[3772,25456,25457],{"class":3949},"    isCreating",[3772,25459,4800],{"class":3945},[3772,25461,6449],{"class":4042},[3772,25463,25464,25466,25468,25470,25472],{"class":3774,"line":4023},[3772,25465,6454],{"class":3949},[3772,25467,4800],{"class":3945},[3772,25469,6459],{"class":4042},[3772,25471,6462],{"class":3945},[3772,25473,4816],{"class":4042},[3772,25475,25476],{"class":3774,"line":4028},[3772,25477,4316],{"class":3945},[3772,25479,25480],{"class":3774,"line":4034},[3772,25481,3965],{"emptyLinePlaceholder":3964},[3772,25483,25484,25486,25488,25490,25492],{"class":3774,"line":4068},[3772,25485,5885],{"class":3980},[3772,25487,5888],{"class":3984},[3772,25489,4800],{"class":3945},[3772,25491,6483],{"class":4042},[3772,25493,5891],{"class":3945},[3772,25495,25496,25498],{"class":3774,"line":4313},[3772,25497,5385],{"class":3949},[3772,25499,5898],{"class":3945},[3772,25501,25502,25504,25506],{"class":3774,"line":4470},[3772,25503,5903],{"class":3949},[3772,25505,4279],{"class":3980},[3772,25507,4806],{"class":3945},[3772,25509,25510,25513,25515],{"class":3774,"line":4879},[3772,25511,25512],{"class":3949},"    isCreating:",[3772,25514,4279],{"class":3980},[3772,25516,4806],{"class":3945},[3772,25518,25519,25521,25523],{"class":3774,"line":4892},[3772,25520,5912],{"class":3949},[3772,25522,5915],{"class":3980},[3772,25524,4806],{"class":3945},[3772,25526,25527],{"class":3774,"line":4903},[3772,25528,4316],{"class":3945},[3772,25530,25531],{"class":3774,"line":4909},[3772,25532,3965],{"emptyLinePlaceholder":3964},[3772,25534,25535,25537,25539,25541,25543,25545],{"class":3774,"line":5521},[3772,25536,3977],{"class":3941},[3772,25538,3981],{"class":3980},[3772,25540,6529],{"class":3984},[3772,25542,3988],{"class":3945},[3772,25544,3846],{"class":3778},[3772,25546,3993],{"class":3945},[3772,25548,25549,25551,25553],{"class":3774,"line":5527},[3772,25550,6540],{"class":3949},[3772,25552,6543],{"class":3781},[3772,25554,4806],{"class":3945},[3772,25556,25557,25559],{"class":3774,"line":5533},[3772,25558,6550],{"class":3949},[3772,25560,4806],{"class":3945},[3772,25562,25563,25565],{"class":3774,"line":5539},[3772,25564,6557],{"class":3949},[3772,25566,4002],{"class":3945},[3772,25568,25569,25572,25574,25576],{"class":3774,"line":5545},[3772,25570,25571],{"class":3778},"        clearError",[3772,25573,5150],{"class":3945},[3772,25575,5153],{"class":3949},[3772,25577,5166],{"class":3945},[3772,25579,25580,25582,25584,25586,25588],{"class":3774,"line":5550},[3772,25581,6598],{"class":3949},[3772,25583,4059],{"class":3945},[3772,25585,5072],{"class":3949},[3772,25587,3988],{"class":3945},[3772,25589,4816],{"class":3980},[3772,25591,25592],{"class":3774,"line":6121},[3772,25593,6621],{"class":3945},[3772,25595,25596],{"class":3774,"line":6131},[3772,25597,4014],{"class":3945},[3772,25599,25600,25602,25604,25606,25608,25610,25612],{"class":3774,"line":6136},[3772,25601,9190],{"class":3778},[3772,25603,4094],{"class":3949},[3772,25605,5179],{"class":3945},[3772,25607,9197],{"class":3949},[3772,25609,5765],{"class":3945},[3772,25611,5768],{"class":3980},[3772,25613,4002],{"class":3945},[3772,25615,25616],{"class":3774,"line":6142},[3772,25617,9215],{"class":3949},[3772,25619,25620],{"class":3774,"line":6150},[3772,25621,25622],{"class":3934},"            \u002F\u002F Обробка GET fetchTrips\n",[3772,25624,25625,25627,25629,25631,25633,25635,25637,25639,25641,25643,25645],{"class":3774,"line":6157},[3772,25626,9221],{"class":3945},[3772,25628,9224],{"class":3778},[3772,25630,5150],{"class":3945},[3772,25632,9229],{"class":3949},[3772,25634,4059],{"class":3945},[3772,25636,9234],{"class":3949},[3772,25638,7128],{"class":3945},[3772,25640,5153],{"class":3949},[3772,25642,5765],{"class":3945},[3772,25644,5768],{"class":3980},[3772,25646,4002],{"class":3945},[3772,25648,25649,25651,25653,25655,25657],{"class":3774,"line":6162},[3772,25650,8815],{"class":3949},[3772,25652,4059],{"class":3945},[3772,25654,6741],{"class":3949},[3772,25656,3988],{"class":3945},[3772,25658,4865],{"class":3980},[3772,25660,25661,25663,25665,25667,25669],{"class":3774,"line":6629},[3772,25662,8815],{"class":3949},[3772,25664,4059],{"class":3945},[3772,25666,5072],{"class":3949},[3772,25668,3988],{"class":3945},[3772,25670,4816],{"class":3980},[3772,25672,25673],{"class":3774,"line":6653},[3772,25674,9263],{"class":3945},[3772,25676,25677,25679,25681,25683,25685,25687,25689,25691,25693,25695,25697,25699,25701],{"class":3774,"line":6698},[3772,25678,9221],{"class":3945},[3772,25680,9224],{"class":3778},[3772,25682,5150],{"class":3945},[3772,25684,9229],{"class":3949},[3772,25686,4059],{"class":3945},[3772,25688,9279],{"class":3949},[3772,25690,7128],{"class":3945},[3772,25692,5153],{"class":3949},[3772,25694,3847],{"class":3945},[3772,25696,5163],{"class":3949},[3772,25698,5765],{"class":3945},[3772,25700,5768],{"class":3980},[3772,25702,4002],{"class":3945},[3772,25704,25705,25707,25709,25711,25713],{"class":3774,"line":6703},[3772,25706,8815],{"class":3949},[3772,25708,4059],{"class":3945},[3772,25710,6741],{"class":3949},[3772,25712,3988],{"class":3945},[3772,25714,9324],{"class":3980},[3772,25716,25717,25719,25721,25723,25725,25727,25729],{"class":3774,"line":6709},[3772,25718,8815],{"class":3949},[3772,25720,4059],{"class":3945},[3772,25722,5237],{"class":3949},[3772,25724,3988],{"class":3945},[3772,25726,5163],{"class":3949},[3772,25728,4059],{"class":3945},[3772,25730,6750],{"class":3949},[3772,25732,25733],{"class":3774,"line":6734},[3772,25734,9263],{"class":3945},[3772,25736,25737,25739,25741,25743,25745,25747,25749,25751,25753,25755,25757,25759,25761],{"class":3774,"line":6753},[3772,25738,9221],{"class":3945},[3772,25740,9224],{"class":3778},[3772,25742,5150],{"class":3945},[3772,25744,9229],{"class":3949},[3772,25746,4059],{"class":3945},[3772,25748,12260],{"class":3949},[3772,25750,7128],{"class":3945},[3772,25752,5153],{"class":3949},[3772,25754,3847],{"class":3945},[3772,25756,5163],{"class":3949},[3772,25758,5765],{"class":3945},[3772,25760,5768],{"class":3980},[3772,25762,4002],{"class":3945},[3772,25764,25765,25767,25769,25771,25773],{"class":3774,"line":6758},[3772,25766,8815],{"class":3949},[3772,25768,4059],{"class":3945},[3772,25770,6741],{"class":3949},[3772,25772,3988],{"class":3945},[3772,25774,9324],{"class":3980},[3772,25776,25777,25779,25781,25783,25785,25787,25789,25791,25793],{"class":3774,"line":6763},[3772,25778,8815],{"class":3949},[3772,25780,4059],{"class":3945},[3772,25782,5072],{"class":3949},[3772,25784,3988],{"class":3945},[3772,25786,5163],{"class":3949},[3772,25788,4059],{"class":3945},[3772,25790,5059],{"class":3949},[3772,25792,12305],{"class":3945},[3772,25794,25795],{"class":3781},"'Не вдалося завантажити поїздки'\n",[3772,25797,25798],{"class":3774,"line":6768},[3772,25799,9263],{"class":3945},[3772,25801,25802],{"class":3774,"line":6773},[3772,25803,3965],{"emptyLinePlaceholder":3964},[3772,25805,25806],{"class":3774,"line":6779},[3772,25807,25808],{"class":3934},"            \u002F\u002F Обробка POST createTrip\n",[3772,25810,25811,25813,25815,25817,25819,25821,25823,25825,25827,25829,25831],{"class":3774,"line":6812},[3772,25812,9221],{"class":3945},[3772,25814,9224],{"class":3778},[3772,25816,5150],{"class":3945},[3772,25818,11976],{"class":3949},[3772,25820,4059],{"class":3945},[3772,25822,9234],{"class":3949},[3772,25824,7128],{"class":3945},[3772,25826,5153],{"class":3949},[3772,25828,5765],{"class":3945},[3772,25830,5768],{"class":3980},[3772,25832,4002],{"class":3945},[3772,25834,25835,25837,25839,25841,25843],{"class":3774,"line":6817},[3772,25836,8815],{"class":3949},[3772,25838,4059],{"class":3945},[3772,25840,22891],{"class":3949},[3772,25842,3988],{"class":3945},[3772,25844,4865],{"class":3980},[3772,25846,25847,25849,25851,25853,25855],{"class":3774,"line":6823},[3772,25848,8815],{"class":3949},[3772,25850,4059],{"class":3945},[3772,25852,5072],{"class":3949},[3772,25854,3988],{"class":3945},[3772,25856,4816],{"class":3980},[3772,25858,25859],{"class":3774,"line":8841},[3772,25860,9263],{"class":3945},[3772,25862,25863,25865,25867,25869,25871,25873,25875,25877,25879,25881,25883,25885,25887],{"class":3774,"line":8865},[3772,25864,9221],{"class":3945},[3772,25866,9224],{"class":3778},[3772,25868,5150],{"class":3945},[3772,25870,11976],{"class":3949},[3772,25872,4059],{"class":3945},[3772,25874,9279],{"class":3949},[3772,25876,7128],{"class":3945},[3772,25878,5153],{"class":3949},[3772,25880,3847],{"class":3945},[3772,25882,5163],{"class":3949},[3772,25884,5765],{"class":3945},[3772,25886,5768],{"class":3980},[3772,25888,4002],{"class":3945},[3772,25890,25891,25893,25895,25897,25899],{"class":3774,"line":8873},[3772,25892,8815],{"class":3949},[3772,25894,4059],{"class":3945},[3772,25896,22891],{"class":3949},[3772,25898,3988],{"class":3945},[3772,25900,9324],{"class":3980},[3772,25902,25903,25905,25907,25909,25911,25913,25915,25917,25919,25921],{"class":3774,"line":8881},[3772,25904,8815],{"class":3949},[3772,25906,4059],{"class":3945},[3772,25908,5237],{"class":3949},[3772,25910,4059],{"class":3945},[3772,25912,8757],{"class":3778},[3772,25914,5150],{"class":3945},[3772,25916,5163],{"class":3949},[3772,25918,4059],{"class":3945},[3772,25920,5059],{"class":3949},[3772,25922,5345],{"class":3945},[3772,25924,25925],{"class":3774,"line":8894},[3772,25926,9263],{"class":3945},[3772,25928,25929,25931,25933,25935,25937,25939,25941,25943,25945,25947,25949,25951,25953],{"class":3774,"line":8902},[3772,25930,9221],{"class":3945},[3772,25932,9224],{"class":3778},[3772,25934,5150],{"class":3945},[3772,25936,11976],{"class":3949},[3772,25938,4059],{"class":3945},[3772,25940,12260],{"class":3949},[3772,25942,7128],{"class":3945},[3772,25944,5153],{"class":3949},[3772,25946,3847],{"class":3945},[3772,25948,5163],{"class":3949},[3772,25950,5765],{"class":3945},[3772,25952,5768],{"class":3980},[3772,25954,4002],{"class":3945},[3772,25956,25957,25959,25961,25963,25965],{"class":3774,"line":8910},[3772,25958,8815],{"class":3949},[3772,25960,4059],{"class":3945},[3772,25962,22891],{"class":3949},[3772,25964,3988],{"class":3945},[3772,25966,9324],{"class":3980},[3772,25968,25969,25971,25973,25975,25977,25979,25981,25983,25985],{"class":3774,"line":8922},[3772,25970,8815],{"class":3949},[3772,25972,4059],{"class":3945},[3772,25974,5072],{"class":3949},[3772,25976,3988],{"class":3945},[3772,25978,5163],{"class":3949},[3772,25980,4059],{"class":3945},[3772,25982,5059],{"class":3949},[3772,25984,12305],{"class":3945},[3772,25986,25987],{"class":3781},"'Не вдалося створити поїздку'\n",[3772,25989,25990],{"class":3774,"line":8928},[3772,25991,9263],{"class":3945},[3772,25993,25994],{"class":3774,"line":8934},[3772,25995,4014],{"class":3945},[3772,25997,25998],{"class":3774,"line":8939},[3772,25999,4020],{"class":3945},[7025,26001,26003],{"id":26002},"скасування-thunk-при-розмонтуванні-компонента","Скасування Thunk при розмонтуванні компонента",[3762,26005,26007],{"className":4129,"code":26006,"language":4131,"meta":3767,"style":3767},"import React, { useEffect } from 'react'\nimport { useAppDispatch } from '@\u002Fstore\u002Fhooks'\nimport { fetchTripsThunk } from '@\u002Fstore\u002Fthunks\u002FtripsThunks'\n\nexport function TripsListScreen() {\n    const dispatch = useAppDispatch()\n\n    useEffect(() => {\n        \u002F\u002F Запускаємо запит і зберігаємо обіцянку\n        const promise = dispatch(fetchTripsThunk())\n\n        return () => {\n            \u002F\u002F При розмонтуванні екрана (перехід назад) скасовуємо HTTP-запит!\n            promise.abort()\n        }\n    }, [dispatch])\n\n    \u002F\u002F ...\n}\n",[3769,26008,26009,26025,26039,26053,26057,26067,26079,26083,26093,26098,26114,26118,26128,26133,26143,26147,26155,26159,26163],{"__ignoreMap":3767},[3772,26010,26011,26013,26015,26017,26019,26021,26023],{"class":3774,"line":3775},[3772,26012,3942],{"class":3941},[3772,26014,14502],{"class":3949},[3772,26016,20886],{"class":3945},[3772,26018,24178],{"class":3949},[3772,26020,3952],{"class":3945},[3772,26022,3955],{"class":3941},[3772,26024,14507],{"class":3781},[3772,26026,26027,26029,26031,26033,26035,26037],{"class":3774,"line":3938},[3772,26028,3942],{"class":3941},[3772,26030,3946],{"class":3945},[3772,26032,14537],{"class":3949},[3772,26034,3952],{"class":3945},[3772,26036,3955],{"class":3941},[3772,26038,14548],{"class":3781},[3772,26040,26041,26043,26045,26047,26049,26051],{"class":3774,"line":3961},[3772,26042,3942],{"class":3941},[3772,26044,3946],{"class":3945},[3772,26046,9229],{"class":3949},[3772,26048,3952],{"class":3945},[3772,26050,3955],{"class":3941},[3772,26052,24213],{"class":3781},[3772,26054,26055],{"class":3774,"line":3968},[3772,26056,3965],{"emptyLinePlaceholder":3964},[3772,26058,26059,26061,26063,26065],{"class":3774,"line":3974},[3772,26060,3977],{"class":3941},[3772,26062,4199],{"class":3980},[3772,26064,24226],{"class":3778},[3772,26066,4205],{"class":3945},[3772,26068,26069,26071,26073,26075,26077],{"class":3774,"line":3996},[3772,26070,10944],{"class":3980},[3772,26072,14600],{"class":3984},[3772,26074,3988],{"class":3945},[3772,26076,14537],{"class":3778},[3772,26078,13941],{"class":3945},[3772,26080,26081],{"class":3774,"line":4005},[3772,26082,3965],{"emptyLinePlaceholder":3964},[3772,26084,26085,26087,26089,26091],{"class":3774,"line":4011},[3772,26086,24249],{"class":3778},[3772,26088,24252],{"class":3945},[3772,26090,5768],{"class":3980},[3772,26092,4002],{"class":3945},[3772,26094,26095],{"class":3774,"line":4017},[3772,26096,26097],{"class":3934},"        \u002F\u002F Запускаємо запит і зберігаємо обіцянку\n",[3772,26099,26100,26102,26104,26106,26108,26110,26112],{"class":3774,"line":4023},[3772,26101,10557],{"class":3980},[3772,26103,24268],{"class":3984},[3772,26105,3988],{"class":3945},[3772,26107,9962],{"class":3778},[3772,26109,5150],{"class":3945},[3772,26111,9229],{"class":3778},[3772,26113,17271],{"class":3945},[3772,26115,26116],{"class":3774,"line":4028},[3772,26117,3965],{"emptyLinePlaceholder":3964},[3772,26119,26120,26122,26124,26126],{"class":3774,"line":4034},[3772,26121,5202],{"class":3941},[3772,26123,16835],{"class":3945},[3772,26125,5768],{"class":3980},[3772,26127,4002],{"class":3945},[3772,26129,26130],{"class":3774,"line":4068},[3772,26131,26132],{"class":3934},"            \u002F\u002F При розмонтуванні екрана (перехід назад) скасовуємо HTTP-запит!\n",[3772,26134,26135,26137,26139,26141],{"class":3774,"line":4313},[3772,26136,24302],{"class":3949},[3772,26138,4059],{"class":3945},[3772,26140,24307],{"class":3778},[3772,26142,13941],{"class":3945},[3772,26144,26145],{"class":3774,"line":4470},[3772,26146,5245],{"class":3945},[3772,26148,26149,26151,26153],{"class":3774,"line":4879},[3772,26150,24334],{"class":3945},[3772,26152,9962],{"class":3949},[3772,26154,24339],{"class":3945},[3772,26156,26157],{"class":3774,"line":4892},[3772,26158,3965],{"emptyLinePlaceholder":3964},[3772,26160,26161],{"class":3774,"line":4903},[3772,26162,18233],{"class":3934},[3772,26164,26165],{"class":3774,"line":4909},[3772,26166,4316],{"class":3945},[4495,26168],{},[3738,26170,26172],{"id":26171},"типові-шаблони-та-best-practices","Типові шаблони та Best Practices",[3747,26174,26176],{"id":26175},"шаблон-1-організація-файлової-структури","Шаблон 1: Організація файлової структури",[3743,26178,26179],{},"Для масштабованих проєктів рекомендується така структура:",[3762,26181,26184],{"className":26182,"code":26183,"language":3910},[3908],"src\u002F\n├── store\u002F\n│   ├── index.ts                 # Конфігурація store\n│   ├── hooks.ts                 # Типізовані хуки (useAppDispatch, useAppSelector)\n│   │\n│   ├── slices\u002F                  # Redux Slices\n│   │   ├── tripsSlice.ts\n│   │   ├── userSlice.ts\n│   │   ├── settingsSlice.ts\n│   │   └── index.ts             # Експорт всіх reducers\n│   │\n│   ├── thunks\u002F                  # Асинхронні дії\n│   │   ├── tripsThunks.ts\n│   │   ├── userThunks.ts\n│   │   └── index.ts\n│   │\n│   ├── selectors\u002F               # Мемоїзовані селектори\n│   │   ├── tripsSelectors.ts\n│   │   ├── userSelectors.ts\n│   │   └── index.ts\n│   │\n│   └── middleware\u002F              # Кастомні middleware\n│       ├── analyticsMiddleware.ts\n│       └── errorLoggerMiddleware.ts\n",[3769,26185,26183],{"__ignoreMap":3767},[5075,26187,26188,26193,26196,26202],{},[3743,26189,26190],{},[3829,26191,26192],{},"Альтернативний підхід: Feature-based структура",[3743,26194,26195],{},"Замість розділення за типом файлів (slices\u002Fthunks\u002Fselectors) можна організувати за фічами:",[3762,26197,26200],{"className":26198,"code":26199,"language":3910},[3908],"src\u002F\n├── features\u002F\n│   ├── trips\u002F\n│   │   ├── tripsSlice.ts\n│   │   ├── tripsThunks.ts\n│   │   ├── tripsSelectors.ts\n│   │   └── types.ts\n│   │\n│   ├── user\u002F\n│   │   ├── userSlice.ts\n│   │   ├── userThunks.ts\n│   │   └── types.ts\n│   │\n│   └── settings\u002F\n│       ├── settingsSlice.ts\n│       └── types.ts\n│\n└── store\u002F\n    ├── index.ts       # Комбінація всіх slices\n    └── hooks.ts\n",[3769,26201,26199],{"__ignoreMap":3767},[3743,26203,26204],{},"Обирайте підхід, що найкраще підходить вашій команді!",[3747,26206,26208],{"id":26207},"шаблон-2-централізований-обробник-помилок","Шаблон 2: Централізований обробник помилок",[3762,26210,26212],{"className":3925,"code":26211,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FerrorSlice.ts\nimport { createSlice, PayloadAction, isRejected } from '@reduxjs\u002Ftoolkit'\n\ninterface ErrorState {\n    message: string | null\n    timestamp: number | null\n    action: string | null\n}\n\nconst initialState: ErrorState = {\n    message: null,\n    timestamp: null,\n    action: null,\n}\n\nexport const errorSlice = createSlice({\n    name: 'error',\n    initialState,\n    reducers: {\n        clearError(state) {\n            state.message = null\n            state.timestamp = null\n            state.action = null\n        },\n    },\n    extraReducers: (builder) => {\n        \u002F\u002F Перехоплюємо ВСІ rejected дії\n        builder.addMatcher(isRejected, (state, action) => {\n            state.message = action.error.message ?? 'Невідома помилка'\n            state.timestamp = Date.now()\n            state.action = action.type\n\n            \u002F\u002F Можна додати логування\n            console.error('[Global Error]', {\n                type: action.type,\n                error: action.error,\n                payload: action.payload,\n            })\n        })\n    },\n})\n\nexport const { clearError } = errorSlice.actions\nexport default errorSlice.reducer\n",[3769,26213,26214,26219,26241,26245,26254,26267,26280,26293,26297,26301,26314,26323,26332,26341,26345,26349,26364,26373,26379,26385,26395,26407,26420,26432,26436,26440,26456,26461,26487,26511,26529,26546,26550,26555,26570,26583,26595,26607,26611,26615,26619,26623,26627,26647],{"__ignoreMap":3767},[3772,26215,26216],{"class":3774,"line":3775},[3772,26217,26218],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fslices\u002FerrorSlice.ts\n",[3772,26220,26221,26223,26225,26227,26229,26231,26233,26235,26237,26239],{"class":3774,"line":3938},[3772,26222,3942],{"class":3941},[3772,26224,3946],{"class":3945},[3772,26226,3846],{"class":3949},[3772,26228,3847],{"class":3945},[3772,26230,6361],{"class":3949},[3772,26232,3847],{"class":3945},[3772,26234,12513],{"class":3949},[3772,26236,3952],{"class":3945},[3772,26238,3955],{"class":3941},[3772,26240,3958],{"class":3781},[3772,26242,26243],{"class":3774,"line":3961},[3772,26244,3965],{"emptyLinePlaceholder":3964},[3772,26246,26247,26249,26252],{"class":3774,"line":3968},[3772,26248,6376],{"class":3980},[3772,26250,26251],{"class":4042}," ErrorState",[3772,26253,4002],{"class":3945},[3772,26255,26256,26259,26261,26263,26265],{"class":3774,"line":3974},[3772,26257,26258],{"class":3949},"    message",[3772,26260,4800],{"class":3945},[3772,26262,6459],{"class":4042},[3772,26264,6462],{"class":3945},[3772,26266,4816],{"class":4042},[3772,26268,26269,26272,26274,26276,26278],{"class":3774,"line":3996},[3772,26270,26271],{"class":3949},"    timestamp",[3772,26273,4800],{"class":3945},[3772,26275,7833],{"class":4042},[3772,26277,6462],{"class":3945},[3772,26279,4816],{"class":4042},[3772,26281,26282,26285,26287,26289,26291],{"class":3774,"line":4005},[3772,26283,26284],{"class":3949},"    action",[3772,26286,4800],{"class":3945},[3772,26288,6459],{"class":4042},[3772,26290,6462],{"class":3945},[3772,26292,4816],{"class":4042},[3772,26294,26295],{"class":3774,"line":4011},[3772,26296,4316],{"class":3945},[3772,26298,26299],{"class":3774,"line":4017},[3772,26300,3965],{"emptyLinePlaceholder":3964},[3772,26302,26303,26305,26307,26309,26312],{"class":3774,"line":4023},[3772,26304,5885],{"class":3980},[3772,26306,5888],{"class":3984},[3772,26308,4800],{"class":3945},[3772,26310,26311],{"class":4042},"ErrorState",[3772,26313,5891],{"class":3945},[3772,26315,26316,26319,26321],{"class":3774,"line":4028},[3772,26317,26318],{"class":3949},"    message:",[3772,26320,5915],{"class":3980},[3772,26322,4806],{"class":3945},[3772,26324,26325,26328,26330],{"class":3774,"line":4034},[3772,26326,26327],{"class":3949},"    timestamp:",[3772,26329,5915],{"class":3980},[3772,26331,4806],{"class":3945},[3772,26333,26334,26337,26339],{"class":3774,"line":4068},[3772,26335,26336],{"class":3949},"    action:",[3772,26338,5915],{"class":3980},[3772,26340,4806],{"class":3945},[3772,26342,26343],{"class":3774,"line":4313},[3772,26344,4316],{"class":3945},[3772,26346,26347],{"class":3774,"line":4470},[3772,26348,3965],{"emptyLinePlaceholder":3964},[3772,26350,26351,26353,26355,26358,26360,26362],{"class":3774,"line":4879},[3772,26352,3977],{"class":3941},[3772,26354,3981],{"class":3980},[3772,26356,26357],{"class":3984}," errorSlice",[3772,26359,3988],{"class":3945},[3772,26361,3846],{"class":3778},[3772,26363,3993],{"class":3945},[3772,26365,26366,26368,26371],{"class":3774,"line":4892},[3772,26367,6540],{"class":3949},[3772,26369,26370],{"class":3781}," 'error'",[3772,26372,4806],{"class":3945},[3772,26374,26375,26377],{"class":3774,"line":4903},[3772,26376,6550],{"class":3949},[3772,26378,4806],{"class":3945},[3772,26380,26381,26383],{"class":3774,"line":4909},[3772,26382,6557],{"class":3949},[3772,26384,4002],{"class":3945},[3772,26386,26387,26389,26391,26393],{"class":3774,"line":5521},[3772,26388,25571],{"class":3778},[3772,26390,5150],{"class":3945},[3772,26392,5153],{"class":3949},[3772,26394,5166],{"class":3945},[3772,26396,26397,26399,26401,26403,26405],{"class":3774,"line":5527},[3772,26398,6598],{"class":3949},[3772,26400,4059],{"class":3945},[3772,26402,13237],{"class":3949},[3772,26404,3988],{"class":3945},[3772,26406,4816],{"class":3980},[3772,26408,26409,26411,26413,26416,26418],{"class":3774,"line":5533},[3772,26410,6598],{"class":3949},[3772,26412,4059],{"class":3945},[3772,26414,26415],{"class":3949},"timestamp",[3772,26417,3988],{"class":3945},[3772,26419,4816],{"class":3980},[3772,26421,26422,26424,26426,26428,26430],{"class":3774,"line":5539},[3772,26423,6598],{"class":3949},[3772,26425,4059],{"class":3945},[3772,26427,5163],{"class":3949},[3772,26429,3988],{"class":3945},[3772,26431,4816],{"class":3980},[3772,26433,26434],{"class":3774,"line":5545},[3772,26435,6621],{"class":3945},[3772,26437,26438],{"class":3774,"line":5550},[3772,26439,4014],{"class":3945},[3772,26441,26442,26444,26446,26448,26450,26452,26454],{"class":3774,"line":6121},[3772,26443,9190],{"class":3778},[3772,26445,4094],{"class":3949},[3772,26447,5179],{"class":3945},[3772,26449,9197],{"class":3949},[3772,26451,5765],{"class":3945},[3772,26453,5768],{"class":3980},[3772,26455,4002],{"class":3945},[3772,26457,26458],{"class":3774,"line":6131},[3772,26459,26460],{"class":3934},"        \u002F\u002F Перехоплюємо ВСІ rejected дії\n",[3772,26462,26463,26465,26467,26469,26471,26473,26475,26477,26479,26481,26483,26485],{"class":3774,"line":6136},[3772,26464,14253],{"class":3949},[3772,26466,4059],{"class":3945},[3772,26468,12494],{"class":3778},[3772,26470,5150],{"class":3945},[3772,26472,12513],{"class":3949},[3772,26474,7128],{"class":3945},[3772,26476,5153],{"class":3949},[3772,26478,3847],{"class":3945},[3772,26480,5163],{"class":3949},[3772,26482,5765],{"class":3945},[3772,26484,5768],{"class":3980},[3772,26486,4002],{"class":3945},[3772,26488,26489,26491,26493,26495,26497,26499,26501,26503,26505,26507,26509],{"class":3774,"line":6142},[3772,26490,6598],{"class":3949},[3772,26492,4059],{"class":3945},[3772,26494,13237],{"class":3949},[3772,26496,3988],{"class":3945},[3772,26498,5163],{"class":3949},[3772,26500,4059],{"class":3945},[3772,26502,5072],{"class":3949},[3772,26504,4059],{"class":3945},[3772,26506,13237],{"class":3949},[3772,26508,12305],{"class":3945},[3772,26510,13242],{"class":3781},[3772,26512,26513,26515,26517,26519,26521,26523,26525,26527],{"class":3774,"line":6150},[3772,26514,6598],{"class":3949},[3772,26516,4059],{"class":3945},[3772,26518,26415],{"class":3949},[3772,26520,3988],{"class":3945},[3772,26522,13933],{"class":3949},[3772,26524,4059],{"class":3945},[3772,26526,13938],{"class":3778},[3772,26528,13941],{"class":3945},[3772,26530,26531,26533,26535,26537,26539,26541,26543],{"class":3774,"line":6157},[3772,26532,6598],{"class":3949},[3772,26534,4059],{"class":3945},[3772,26536,5163],{"class":3949},[3772,26538,3988],{"class":3945},[3772,26540,5163],{"class":3949},[3772,26542,4059],{"class":3945},[3772,26544,26545],{"class":3949},"type\n",[3772,26547,26548],{"class":3774,"line":6162},[3772,26549,3965],{"emptyLinePlaceholder":3964},[3772,26551,26552],{"class":3774,"line":6629},[3772,26553,26554],{"class":3934},"            \u002F\u002F Можна додати логування\n",[3772,26556,26557,26559,26561,26563,26565,26568],{"class":3774,"line":6653},[3772,26558,24314],{"class":3949},[3772,26560,4059],{"class":3945},[3772,26562,5072],{"class":3778},[3772,26564,5150],{"class":3945},[3772,26566,26567],{"class":3781},"'[Global Error]'",[3772,26569,15192],{"class":3945},[3772,26571,26572,26575,26577,26579,26581],{"class":3774,"line":6698},[3772,26573,26574],{"class":3949},"                type:",[3772,26576,7262],{"class":3949},[3772,26578,4059],{"class":3945},[3772,26580,5048],{"class":3949},[3772,26582,4806],{"class":3945},[3772,26584,26585,26587,26589,26591,26593],{"class":3774,"line":6703},[3772,26586,6124],{"class":3949},[3772,26588,7262],{"class":3949},[3772,26590,4059],{"class":3945},[3772,26592,5072],{"class":3949},[3772,26594,4806],{"class":3945},[3772,26596,26597,26599,26601,26603,26605],{"class":3774,"line":6709},[3772,26598,10229],{"class":3949},[3772,26600,7262],{"class":3949},[3772,26602,4059],{"class":3945},[3772,26604,5059],{"class":3949},[3772,26606,4806],{"class":3945},[3772,26608,26609],{"class":3774,"line":6734},[3772,26610,9263],{"class":3945},[3772,26612,26613],{"class":3774,"line":6753},[3772,26614,14303],{"class":3945},[3772,26616,26617],{"class":3774,"line":6758},[3772,26618,4014],{"class":3945},[3772,26620,26621],{"class":3774,"line":6763},[3772,26622,4020],{"class":3945},[3772,26624,26625],{"class":3774,"line":6768},[3772,26626,3965],{"emptyLinePlaceholder":3964},[3772,26628,26629,26631,26633,26635,26638,26640,26643,26645],{"class":3774,"line":6773},[3772,26630,3977],{"class":3941},[3772,26632,3981],{"class":3980},[3772,26634,3946],{"class":3945},[3772,26636,26637],{"class":3984},"clearError",[3772,26639,6801],{"class":3945},[3772,26641,26642],{"class":3949},"errorSlice",[3772,26644,4059],{"class":3945},[3772,26646,6809],{"class":3949},[3772,26648,26649,26651,26653,26655,26657],{"class":3774,"line":6779},[3772,26650,3977],{"class":3941},[3772,26652,4196],{"class":3941},[3772,26654,26357],{"class":3949},[3772,26656,4059],{"class":3945},[3772,26658,6834],{"class":3949},[3747,26660,26662],{"id":26661},"шаблон-3-loading-states-pattern","Шаблон 3: Loading States Pattern",[3762,26664,26666],{"className":3925,"code":26665,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FtripsSlice.ts\ninterface TripsState {\n    items: Trip[]\n\n    \u002F\u002F Різні типи loading для різних операцій\n    loading: {\n        fetch: boolean \u002F\u002F Завантаження списку\n        create: boolean \u002F\u002F Створення нової поїздки\n        update: boolean \u002F\u002F Оновлення існуючої\n        delete: boolean \u002F\u002F Видалення\n    }\n\n    error: string | null\n}\n\nconst initialState: TripsState = {\n    items: [],\n    loading: {\n        fetch: false,\n        create: false,\n        update: false,\n        delete: false,\n    },\n    error: null,\n}\n",[3769,26667,26668,26672,26680,26690,26694,26699,26705,26717,26729,26741,26753,26757,26761,26773,26777,26781,26793,26799,26805,26814,26823,26832,26841,26845,26853],{"__ignoreMap":3767},[3772,26669,26670],{"class":3774,"line":3775},[3772,26671,6348],{"class":3934},[3772,26673,26674,26676,26678],{"class":3774,"line":3938},[3772,26675,6376],{"class":3980},[3772,26677,6424],{"class":4042},[3772,26679,4002],{"class":3945},[3772,26681,26682,26684,26686,26688],{"class":3774,"line":3961},[3772,26683,6431],{"class":3949},[3772,26685,4800],{"class":3945},[3772,26687,6436],{"class":4042},[3772,26689,6439],{"class":3945},[3772,26691,26692],{"class":3774,"line":3968},[3772,26693,3965],{"emptyLinePlaceholder":3964},[3772,26695,26696],{"class":3774,"line":3974},[3772,26697,26698],{"class":3934},"    \u002F\u002F Різні типи loading для різних операцій\n",[3772,26700,26701,26703],{"class":3774,"line":3996},[3772,26702,6444],{"class":3949},[3772,26704,4723],{"class":3945},[3772,26706,26707,26710,26712,26714],{"class":3774,"line":4005},[3772,26708,26709],{"class":3949},"        fetch",[3772,26711,4800],{"class":3945},[3772,26713,6729],{"class":4042},[3772,26715,26716],{"class":3934}," \u002F\u002F Завантаження списку\n",[3772,26718,26719,26722,26724,26726],{"class":3774,"line":4011},[3772,26720,26721],{"class":3949},"        create",[3772,26723,4800],{"class":3945},[3772,26725,6729],{"class":4042},[3772,26727,26728],{"class":3934}," \u002F\u002F Створення нової поїздки\n",[3772,26730,26731,26734,26736,26738],{"class":3774,"line":4017},[3772,26732,26733],{"class":3949},"        update",[3772,26735,4800],{"class":3945},[3772,26737,6729],{"class":4042},[3772,26739,26740],{"class":3934}," \u002F\u002F Оновлення існуючої\n",[3772,26742,26743,26746,26748,26750],{"class":3774,"line":4023},[3772,26744,26745],{"class":3949},"        delete",[3772,26747,4800],{"class":3945},[3772,26749,6729],{"class":4042},[3772,26751,26752],{"class":3934}," \u002F\u002F Видалення\n",[3772,26754,26755],{"class":3774,"line":4028},[3772,26756,4906],{"class":3945},[3772,26758,26759],{"class":3774,"line":4034},[3772,26760,3965],{"emptyLinePlaceholder":3964},[3772,26762,26763,26765,26767,26769,26771],{"class":3774,"line":4068},[3772,26764,6454],{"class":3949},[3772,26766,4800],{"class":3945},[3772,26768,6459],{"class":4042},[3772,26770,6462],{"class":3945},[3772,26772,4816],{"class":4042},[3772,26774,26775],{"class":3774,"line":4313},[3772,26776,4316],{"class":3945},[3772,26778,26779],{"class":3774,"line":4470},[3772,26780,3965],{"emptyLinePlaceholder":3964},[3772,26782,26783,26785,26787,26789,26791],{"class":3774,"line":4879},[3772,26784,5885],{"class":3980},[3772,26786,5888],{"class":3984},[3772,26788,4800],{"class":3945},[3772,26790,6483],{"class":4042},[3772,26792,5891],{"class":3945},[3772,26794,26795,26797],{"class":3774,"line":4892},[3772,26796,5385],{"class":3949},[3772,26798,5898],{"class":3945},[3772,26800,26801,26803],{"class":3774,"line":4903},[3772,26802,5903],{"class":3949},[3772,26804,4002],{"class":3945},[3772,26806,26807,26810,26812],{"class":3774,"line":4909},[3772,26808,26809],{"class":3949},"        fetch:",[3772,26811,4279],{"class":3980},[3772,26813,4806],{"class":3945},[3772,26815,26816,26819,26821],{"class":3774,"line":5521},[3772,26817,26818],{"class":3949},"        create:",[3772,26820,4279],{"class":3980},[3772,26822,4806],{"class":3945},[3772,26824,26825,26828,26830],{"class":3774,"line":5527},[3772,26826,26827],{"class":3949},"        update:",[3772,26829,4279],{"class":3980},[3772,26831,4806],{"class":3945},[3772,26833,26834,26837,26839],{"class":3774,"line":5533},[3772,26835,26836],{"class":3949},"        delete:",[3772,26838,4279],{"class":3980},[3772,26840,4806],{"class":3945},[3772,26842,26843],{"class":3774,"line":5539},[3772,26844,4014],{"class":3945},[3772,26846,26847,26849,26851],{"class":3774,"line":5545},[3772,26848,5912],{"class":3949},[3772,26850,5915],{"class":3980},[3772,26852,4806],{"class":3945},[3772,26854,26855],{"class":3774,"line":5550},[3772,26856,4316],{"class":3945},[3747,26858,26860],{"id":26859},"best-practices-що-робити-і-чого-уникати","Best Practices: Що робити і чого уникати",[3755,26862,26863,27044],{},[3758,26864,26866,26871,26897,26902,26957,26962],{"label":26865},"✅ Робити",[3743,26867,26868],{},[3829,26869,26870],{},"1. Нормалізуйте складні дані через createEntityAdapter",[3762,26872,26874],{"className":3925,"code":26873,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ✅ ДОБРЕ: Пошук за ID миттєвий O(1)\nconst tripsAdapter = createEntityAdapter\u003CTrip>()\n",[3769,26875,26876,26881],{"__ignoreMap":3767},[3772,26877,26878],{"class":3774,"line":3775},[3772,26879,26880],{"class":3934},"\u002F\u002F ✅ ДОБРЕ: Пошук за ID миттєвий O(1)\n",[3772,26882,26883,26885,26887,26889,26891,26893,26895],{"class":3774,"line":3938},[3772,26884,5885],{"class":3980},[3772,26886,19376],{"class":3984},[3772,26888,3988],{"class":3945},[3772,26890,19252],{"class":3778},[3772,26892,4051],{"class":3945},[3772,26894,6436],{"class":4042},[3772,26896,17774],{"class":3945},[3743,26898,26899],{},[3829,26900,26901],{},"2. Використовуйте мемоїзовані селектори",[3762,26903,26905],{"className":3925,"code":26904,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ✅ ДОБРЕ: Запобігає зайвим перерахункам\nconst selectFilteredTrips = createSelector([selectAllTrips, selectFilters], (trips, filters) => trips.filter(\u002F* ... *\u002F))\n",[3769,26906,26907,26912],{"__ignoreMap":3767},[3772,26908,26909],{"class":3774,"line":3775},[3772,26910,26911],{"class":3934},"\u002F\u002F ✅ ДОБРЕ: Запобігає зайвим перерахункам\n",[3772,26913,26914,26916,26918,26920,26922,26924,26927,26929,26932,26934,26936,26938,26940,26942,26944,26946,26948,26950,26952,26955],{"class":3774,"line":3938},[3772,26915,5885],{"class":3980},[3772,26917,18131],{"class":3984},[3772,26919,3988],{"class":3945},[3772,26921,16461],{"class":3778},[3772,26923,18629],{"class":3945},[3772,26925,26926],{"class":3949},"selectAllTrips",[3772,26928,3847],{"class":3945},[3772,26930,26931],{"class":3949},"selectFilters",[3772,26933,16483],{"class":3945},[3772,26935,7557],{"class":3949},[3772,26937,3847],{"class":3945},[3772,26939,10790],{"class":3949},[3772,26941,5765],{"class":3945},[3772,26943,5768],{"class":3980},[3772,26945,10947],{"class":3949},[3772,26947,4059],{"class":3945},[3772,26949,6053],{"class":3778},[3772,26951,5150],{"class":3945},[3772,26953,26954],{"class":3934},"\u002F* ... *\u002F",[3772,26956,10331],{"class":3945},[3743,26958,26959],{},[3829,26960,26961],{},"3. Розділяйте синхронні та асинхронні дії",[3762,26963,26965],{"className":3925,"code":26964,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ✅ ДОБРЕ: Чітке розділення\nreducers: {\n    setSelectedTrip(state, action) { ... }  \u002F\u002F Локальні зміни\n},\nextraReducers: (builder) => {\n    builder.addCase(fetchTripsThunk.fulfilled, ...)  \u002F\u002F Мережеві запити\n}\n",[3769,26966,26967,26972,26978,26997,27002,27017,27040],{"__ignoreMap":3767},[3772,26968,26969],{"class":3774,"line":3775},[3772,26970,26971],{"class":3934},"\u002F\u002F ✅ ДОБРЕ: Чітке розділення\n",[3772,26973,26974,26976],{"class":3774,"line":3938},[3772,26975,8385],{"class":4719},[3772,26977,4723],{"class":3945},[3772,26979,26980,26983,26985,26987,26989,26991,26994],{"class":3774,"line":3961},[3772,26981,26982],{"class":3778},"    setSelectedTrip",[3772,26984,5150],{"class":3945},[3772,26986,5153],{"class":3949},[3772,26988,3847],{"class":3945},[3772,26990,5163],{"class":3949},[3772,26992,26993],{"class":3945},") { ... }  ",[3772,26995,26996],{"class":3934},"\u002F\u002F Локальні зміни\n",[3772,26998,26999],{"class":3774,"line":3968},[3772,27000,27001],{"class":3945},"},\n",[3772,27003,27004,27006,27009,27011,27013,27015],{"class":3774,"line":3974},[3772,27005,8393],{"class":4719},[3772,27007,27008],{"class":3945},": (",[3772,27010,9197],{"class":3949},[3772,27012,5765],{"class":3945},[3772,27014,5768],{"class":3980},[3772,27016,4002],{"class":3945},[3772,27018,27019,27022,27024,27026,27028,27030,27032,27034,27037],{"class":3774,"line":3996},[3772,27020,27021],{"class":3949},"    builder",[3772,27023,4059],{"class":3945},[3772,27025,9224],{"class":3778},[3772,27027,5150],{"class":3945},[3772,27029,9229],{"class":3949},[3772,27031,4059],{"class":3945},[3772,27033,9279],{"class":3949},[3772,27035,27036],{"class":3945},", ...)  ",[3772,27038,27039],{"class":3934},"\u002F\u002F Мережеві запити\n",[3772,27041,27042],{"class":3774,"line":4005},[3772,27043,4316],{"class":3945},[3758,27045,27047,27052,27129,27134,27212,27217],{"label":27046},"❌ Не робити",[3743,27048,27049],{},[3829,27050,27051],{},"1. Не зберігайте похідні дані",[3762,27053,27055],{"className":3925,"code":27054,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОГАНО: Дублювання даних\n{\n    trips: [...],\n    tripCount: 10        \u002F\u002F Можна обчислити з trips.length\n}\n\n\u002F\u002F ✅ ДОБРЕ: Обчислюйте через селектори\nconst selectTripCount = (state) => state.trips.items.length\n",[3769,27056,27057,27062,27066,27073,27086,27090,27094,27099],{"__ignoreMap":3767},[3772,27058,27059],{"class":3774,"line":3775},[3772,27060,27061],{"class":3934},"\u002F\u002F ❌ ПОГАНО: Дублювання даних\n",[3772,27063,27064],{"class":3774,"line":3938},[3772,27065,4714],{"class":3945},[3772,27067,27068,27070],{"class":3774,"line":3961},[3772,27069,4720],{"class":4719},[3772,27071,27072],{"class":3945},": [...],\n",[3772,27074,27075,27078,27080,27083],{"class":3774,"line":3968},[3772,27076,27077],{"class":4719},"    tripCount",[3772,27079,4800],{"class":3945},[3772,27081,27082],{"class":8916},"10",[3772,27084,27085],{"class":3934},"        \u002F\u002F Можна обчислити з trips.length\n",[3772,27087,27088],{"class":3774,"line":3974},[3772,27089,4316],{"class":3945},[3772,27091,27092],{"class":3774,"line":3996},[3772,27093,3965],{"emptyLinePlaceholder":3964},[3772,27095,27096],{"class":3774,"line":4005},[3772,27097,27098],{"class":3934},"\u002F\u002F ✅ ДОБРЕ: Обчислюйте через селектори\n",[3772,27100,27101,27103,27106,27108,27110,27112,27114,27116,27118,27120,27122,27124,27126],{"class":3774,"line":4011},[3772,27102,5885],{"class":3980},[3772,27104,27105],{"class":3778}," selectTripCount",[3772,27107,5759],{"class":3945},[3772,27109,5153],{"class":3949},[3772,27111,5765],{"class":3945},[3772,27113,5768],{"class":3980},[3772,27115,5353],{"class":3949},[3772,27117,4059],{"class":3945},[3772,27119,7557],{"class":3949},[3772,27121,4059],{"class":3945},[3772,27123,5237],{"class":3949},[3772,27125,4059],{"class":3945},[3772,27127,27128],{"class":3949},"length\n",[3743,27130,27131],{},[3829,27132,27133],{},"2. Не мутуйте стан поза reducers",[3762,27135,27137],{"className":3925,"code":27136,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОГАНО:\nconst trips = useAppSelector((state) => state.trips.items)\ntrips.push(newTrip) \u002F\u002F Мутація!\n\n\u002F\u002F ✅ ДОБРЕ:\ndispatch(addTrip(newTrip))\n",[3769,27138,27139,27143,27173,27190,27194,27198],{"__ignoreMap":3767},[3772,27140,27141],{"class":3774,"line":3775},[3772,27142,16565],{"class":3934},[3772,27144,27145,27147,27149,27151,27153,27155,27157,27159,27161,27163,27165,27167,27169,27171],{"class":3774,"line":3938},[3772,27146,5885],{"class":3980},[3772,27148,10947],{"class":3984},[3772,27150,3988],{"class":3945},[3772,27152,10952],{"class":3778},[3772,27154,6056],{"class":3945},[3772,27156,5153],{"class":3949},[3772,27158,5765],{"class":3945},[3772,27160,5768],{"class":3980},[3772,27162,5353],{"class":3949},[3772,27164,4059],{"class":3945},[3772,27166,7557],{"class":3949},[3772,27168,4059],{"class":3945},[3772,27170,5237],{"class":3949},[3772,27172,5345],{"class":3945},[3772,27174,27175,27177,27179,27181,27183,27185,27187],{"class":3774,"line":3961},[3772,27176,7557],{"class":3949},[3772,27178,4059],{"class":3945},[3772,27180,5337],{"class":3778},[3772,27182,5150],{"class":3945},[3772,27184,10983],{"class":3949},[3772,27186,5765],{"class":3945},[3772,27188,27189],{"class":3934},"\u002F\u002F Мутація!\n",[3772,27191,27192],{"class":3774,"line":3968},[3772,27193,3965],{"emptyLinePlaceholder":3964},[3772,27195,27196],{"class":3774,"line":3974},[3772,27197,16655],{"class":3934},[3772,27199,27200,27202,27204,27206,27208,27210],{"class":3774,"line":3996},[3772,27201,9962],{"class":3778},[3772,27203,5150],{"class":3945},[3772,27205,6788],{"class":3778},[3772,27207,5150],{"class":3945},[3772,27209,10983],{"class":3949},[3772,27211,10331],{"class":3945},[3743,27213,27214],{},[3829,27215,27216],{},"3. Не використовуйте несеріалізовані типи",[3762,27218,27220],{"className":3925,"code":27219,"language":3927,"meta":3767,"style":3767},"\u002F\u002F ❌ ПОГАНО:\ninterface State {\n    startDate: Date \u002F\u002F Несеріалізовано!\n    onComplete: () => void \u002F\u002F Функція!\n}\n\n\u002F\u002F ✅ ДОБРЕ:\ninterface State {\n    startDate: string \u002F\u002F ISO рядок\n}\n",[3769,27221,27222,27226,27235,27246,27262,27266,27270,27274,27282,27293],{"__ignoreMap":3767},[3772,27223,27224],{"class":3774,"line":3775},[3772,27225,16565],{"class":3934},[3772,27227,27228,27230,27233],{"class":3774,"line":3938},[3772,27229,6376],{"class":3980},[3772,27231,27232],{"class":4042}," State",[3772,27234,4002],{"class":3945},[3772,27236,27237,27239,27241,27243],{"class":3774,"line":3961},[3772,27238,22500],{"class":3949},[3772,27240,4800],{"class":3945},[3772,27242,13933],{"class":4042},[3772,27244,27245],{"class":3934}," \u002F\u002F Несеріалізовано!\n",[3772,27247,27248,27251,27254,27256,27259],{"class":3774,"line":3968},[3772,27249,27250],{"class":3778},"    onComplete",[3772,27252,27253],{"class":3945},": () ",[3772,27255,5768],{"class":3980},[3772,27257,27258],{"class":4042}," void",[3772,27260,27261],{"class":3934}," \u002F\u002F Функція!\n",[3772,27263,27264],{"class":3774,"line":3974},[3772,27265,4316],{"class":3945},[3772,27267,27268],{"class":3774,"line":3996},[3772,27269,3965],{"emptyLinePlaceholder":3964},[3772,27271,27272],{"class":3774,"line":4005},[3772,27273,16655],{"class":3934},[3772,27275,27276,27278,27280],{"class":3774,"line":4011},[3772,27277,6376],{"class":3980},[3772,27279,27232],{"class":4042},[3772,27281,4002],{"class":3945},[3772,27283,27284,27286,27288,27290],{"class":3774,"line":4017},[3772,27285,22500],{"class":3949},[3772,27287,4800],{"class":3945},[3772,27289,6459],{"class":4042},[3772,27291,27292],{"class":3934}," \u002F\u002F ISO рядок\n",[3772,27294,27295],{"class":3774,"line":4023},[3772,27296,4316],{"class":3945},[4495,27298],{},[3738,27300,27302],{"id":27301},"плюси-та-мінуси-асинхронних-запитів-через-thunk","Плюси та мінуси асинхронних запитів через Thunk",[3743,27304,27305,27306,27308],{},"Використання ",[3769,27307,3853],{}," для керування серверними даними має чіткі інженерні компроміси, які важливо розуміти перед вибором архітектури.",[3755,27310,27311,27371],{},[3758,27312,27314],{"label":27313},"Переваги (Плюси) ✅",[4588,27315,27316,27327,27340,27353,27359],{},[3836,27317,27318,27321,27322,3869,27324,27326],{},[3829,27319,27320],{},"Єдине глобальне джерело істини:","\nУсі компоненти застосунку мають миттєвий доступ до завантажених даних, стану ",[3769,27323,6741],{},[3769,27325,5072],{}," через єдиний селектор без передавання пропсів через дерево.",[3836,27328,27329,27332,27333,27336,27337,27339],{},[3829,27330,27331],{},"Повний контроль над логікою трансформації:","\nУсередині thunk або редуктора ви маєте прямий доступ до ",[3769,27334,27335],{},"getState()"," і можете комбінувати дані з різних слайсів, нормалізувати структуру через ",[3769,27338,19252],{}," чи виконувати багатоетапні ланцюжки запитів.",[3836,27341,27342,27345,27346,3847,27348,3847,27350,27352],{},[3829,27343,27344],{},"Передбачуваність і Time-Travel Debugging:","\nКожен крок запиту (",[3769,27347,9234],{},[3769,27349,9279],{},[3769,27351,12260],{},") фіксується як окрема дія у Redux DevTools з точним payload і таймстемпом. Це дозволяє легко відтворювати баги мережі.",[3836,27354,27355,27358],{},[3829,27356,27357],{},"Легкість тестування:","\nThunk і редуктори можна ізольовано протестувати модульними тестами Jest без потреби мокати DOM чи рендерити компоненти.",[3836,27360,27361,27370],{},[3829,27362,27363,27364,3869,27367,7779],{},"Вбудовані засоби захисту (",[3769,27365,27366],{},"condition",[3769,27368,27369],{},"AbortController","\nМожливість легко скасовувати запити при unmount та блокувати паралельні дублікати запитів без сторонніх бібліотек.",[3758,27372,27374],{"label":27373},"Недоліки (Мінуси) ⚠️",[4588,27375,27376,27391,27404,27420,27432],{},[3836,27377,27378,27381,27382,3847,27384,3847,27386,27388,27389,4059],{},[3829,27379,27380],{},"Великий обсяг шаблонного коду (Boilerplate):","\nДля кожного ендпоінта потрібно вручну оголошувати поля у стані (",[3769,27383,5237],{},[3769,27385,6741],{},[3769,27387,5072],{},"), створювати thunk і прописувати три кейси в ",[3769,27390,8393],{},[3836,27392,27393,27396,27397,27400,27401,27403],{},[3829,27394,27395],{},"Відсутність автоматичного кешування та дедуплікації:","\nЯкщо два незалежних компоненти на одному екрані викликають ",[3769,27398,27399],{},"dispatch(fetchTripsThunk())",", буде виконано два реальних HTTP-запити (якщо не налаштувати ",[3769,27402,27366],{}," вручну).",[3836,27405,27406,27409,27410,27412,27413,27415,27416,27419],{},[3829,27407,27408],{},"Складність підтримки інвалідації кешу:","\nПісля виклику ",[3769,27411,11976],{}," розробник повинен вручну оновити стан у ",[3769,27414,6804],{}," або вручну викликати ",[3769,27417,27418],{},"fetchTripsThunk()",", щоб синхронізувати список.",[3836,27421,27422,27425,27426,3869,27429,4059],{},[3829,27423,27424],{},"Немає вбудованого Polling, Refetch on Focus \u002F Network Reconnect:","\nДля повторного завантаження при поверненні застосунку з фону чи появі інтернету потрібно писати кастомні хуки або слухачі ",[3769,27427,27428],{},"AppState",[3769,27430,27431],{},"NetInfo",[3836,27433,27434,27437],{},[3829,27435,27436],{},"Ручне керування пам'яттю (Garbage Collection):","\nДані залишаються в пам'яті store назавжди, доки їх явно не очистять.",[3747,27439,27441],{"id":27440},"порівняльна-таблиця-підходи-до-асинхронних-запитів-у-react-native","Порівняльна таблиця: Підходи до асинхронних запитів у React Native",[12405,27443,27444,27473],{},[12408,27445,27446],{},[12411,27447,27448,27452,27457,27466],{},[12414,27449,27451],{"align":27450},"left","Критерій",[12414,27453,27454,27456],{"align":27450},[3769,27455,3853],{}," (RTK)",[12414,27458,27459,27462,27463],{"align":27450},[3769,27460,27461],{},"RTK Query"," \u002F ",[3769,27464,27465],{},"TanStack Query",[12414,27467,27468,27470,27471],{"align":27450},[3769,27469,24178],{}," + локальний ",[3769,27472,4534],{},[12426,27474,27475,27491,27507,27523,27537,27556],{},[12411,27476,27477,27482,27485,27488],{},[12431,27478,27479],{"align":27450},[3829,27480,27481],{},"Призначення",[12431,27483,27484],{"align":27450},"Глобальний клієнтський стан + складні ланцюжки дій",[12431,27486,27487],{"align":27450},"Декларативний серверний стан і кеш",[12431,27489,27490],{"align":27450},"Локальний стан одного компонента",[12411,27492,27493,27498,27501,27504],{},[12431,27494,27495],{"align":27450},[3829,27496,27497],{},"Обсяг коду (Boilerplate)",[12431,27499,27500],{"align":27450},"Середній (потрібні слайс + thunk + extraReducers)",[12431,27502,27503],{"align":27450},"Мінімальний (лише опис ендпоінта)",[12431,27505,27506],{"align":27450},"Мінімальний для одного компонента",[12411,27508,27509,27514,27517,27520],{},[12431,27510,27511],{"align":27450},[3829,27512,27513],{},"Автоматичне кешування",[12431,27515,27516],{"align":27450},"❌ Потрібно писати вручну",[12431,27518,27519],{"align":27450},"✅ Автоматично з TTL та Garbage Collection",[12431,27521,27522],{"align":27450},"❌ Відсутнє",[12411,27524,27525,27530,27532,27535],{},[12431,27526,27527],{"align":27450},[3829,27528,27529],{},"Авто-рефетч при фокусі\u002Fмережі",[12431,27531,27516],{"align":27450},[12431,27533,27534],{"align":27450},"✅ Вбудовано з коробки",[12431,27536,27516],{"align":27450},[12411,27538,27539,27544,27547,27553],{},[12431,27540,27541],{"align":27450},[3829,27542,27543],{},"Оптимістичні оновлення",[12431,27545,27546],{"align":27450},"✅ Гнучкий повний контроль над Rollback",[12431,27548,27549,27550],{"align":27450},"✅ Підтримується через ",[3769,27551,27552],{},"onQueryStarted",[12431,27554,27555],{"align":27450},"⚠️ Складно реалізувати масштабовано",[12411,27557,27558,27563,27566,27569],{},[12431,27559,27560],{"align":27450},[3829,27561,27562],{},"Дебаг у DevTools",[12431,27564,27565],{"align":27450},"✅ Повний таймлайн дій у Redux DevTools",[12431,27567,27568],{"align":27450},"✅ Спеціалізовані інспектори кешу",[12431,27570,27571,27572,27575],{"align":27450},"❌ Лише ",[3769,27573,27574],{},"console.log"," або React Profiler",[5075,27577,27578,27583],{},[3743,27579,27580],{},[3829,27581,27582],{},"Коли обирати createAsyncThunk:",[3833,27584,27585,27588,27591],{},[3836,27586,27587],{},"Коли асинхронна дія є частиною складного клієнтського процесу (наприклад, мультистеп майстер створення поїздки, збереження в SQLite та паралельне оновлення кількох слайсів).",[3836,27589,27590],{},"Коли для роботи застосунку потрібен максимальний контроль над кожною мутацією стану.",[3836,27592,27593,27594,27596],{},"Для стандартного отримання списків та CRUD операцій з кешуванням у наступній статті ми розглянемо ",[3829,27595,27461],{},", який усуває потребу писати thunk-и вручну.",[4495,27598],{},[3738,27600,27602],{"id":27601},"патерн-оптимістичні-оновлення-optimistic-updates-у-redux","Патерн: Оптимістичні оновлення (Optimistic Updates) у Redux",[3743,27604,27605,27606,27609,27610,7779],{},"При повільному 3G-інтернеті користувач не повинен чекати 2 секунди, щоб побачити зафарбоване сердечко «Лайк». Інтерфейс повинен змінюватися ",[3829,27607,27608],{},"миттєво",", а у випадку серверної помилки — автоматично повертатися до попереднього стану (",[4508,27611,27612],{},"Rollback",[3762,27614,27616],{"className":3925,"code":27615,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FlikesSlice.ts\nimport { createSlice, createAsyncThunk } from '@reduxjs\u002Ftoolkit'\nimport { apiClient } from '@\u002Fapi\u002Fclient'\nimport type { RootState } from '..\u002Findex'\n\nexport const toggleTripLikeThunk = createAsyncThunk\u003C\n    { tripId: string; isLiked: boolean },\n    { tripId: string },\n    { state: RootState; rejectValue: { tripId: string; previousLikedState: boolean } }\n>('trips\u002FtoggleLike', async ({ tripId }, { getState, rejectWithValue }) => {\n    const previousLikedState = getState().likes.byTripId[tripId] ?? false\n    try {\n        const response = await apiClient.post(`\u002Ftrips\u002F${tripId}\u002Flike`, {\n            liked: !previousLikedState,\n        })\n        return { tripId, isLiked: response.data.liked }\n    } catch (error) {\n        \u002F\u002F У разі збою повертаємо попередній стан для відкату!\n        return rejectWithValue({ tripId, previousLikedState })\n    }\n})\n\ninterface LikesState {\n    byTripId: Record\u003Cstring, boolean>\n}\n\nconst initialState: LikesState = { byTripId: {} }\n\nexport const likesSlice = createSlice({\n    name: 'likes',\n    initialState,\n    reducers: {},\n    extraReducers: (builder) => {\n        builder\n            \u002F\u002F 1. ОПТИМІСТИЧНЕ ОНОВЛЕННЯ: Миттєво змінюємо UI при pending!\n            .addCase(toggleTripLikeThunk.pending, (state, action) => {\n                const { tripId } = action.meta.arg\n                const current = state.byTripId[tripId] ?? false\n                state.byTripId[tripId] = !current\n            })\n            \u002F\u002F 2. У разі успіху фіксуємо точну відповідь сервера\n            .addCase(toggleTripLikeThunk.fulfilled, (state, action) => {\n                state.byTripId[action.payload.tripId] = action.payload.isLiked\n            })\n            \u002F\u002F 3. ВІДКАТ (ROLLBACK): Повертаємо попереднє значення при помилці\n            .addCase(toggleTripLikeThunk.rejected, (state, action) => {\n                if (action.payload) {\n                    state.byTripId[action.payload.tripId] = action.payload.previousLikedState\n                }\n            })\n    },\n})\n",[3769,27617,27618,27622,27640,27654,27670,27674,27689,27709,27721,27755,27784,27811,27817,27847,27857,27861,27886,27898,27903,27919,27923,27927,27931,27939,27957,27961,27965,27983,27987,28001,28009,28015,28021,28037,28041,28046,28075,28095,28118,28135,28139,28144,28172,28204,28208,28213,28241,28255,28288,28292,28296,28300],{"__ignoreMap":3767},[3772,27619,27620],{"class":3774,"line":3775},[3772,27621,15318],{"class":3934},[3772,27623,27624,27626,27628,27630,27632,27634,27636,27638],{"class":3774,"line":3938},[3772,27625,3942],{"class":3941},[3772,27627,3946],{"class":3945},[3772,27629,3846],{"class":3949},[3772,27631,3847],{"class":3945},[3772,27633,3853],{"class":3949},[3772,27635,3952],{"class":3945},[3772,27637,3955],{"class":3941},[3772,27639,3958],{"class":3781},[3772,27641,27642,27644,27646,27648,27650,27652],{"class":3774,"line":3961},[3772,27643,3942],{"class":3941},[3772,27645,3946],{"class":3945},[3772,27647,14944],{"class":3949},[3772,27649,3952],{"class":3945},[3772,27651,3955],{"class":3941},[3772,27653,14951],{"class":3781},[3772,27655,27656,27658,27660,27662,27664,27666,27668],{"class":3774,"line":3968},[3772,27657,3942],{"class":3941},[3772,27659,4039],{"class":3941},[3772,27661,3946],{"class":3945},[3772,27663,14962],{"class":3949},[3772,27665,3952],{"class":3945},[3772,27667,3955],{"class":3941},[3772,27669,14969],{"class":3781},[3772,27671,27672],{"class":3774,"line":3974},[3772,27673,3965],{"emptyLinePlaceholder":3964},[3772,27675,27676,27678,27680,27683,27685,27687],{"class":3774,"line":3996},[3772,27677,3977],{"class":3941},[3772,27679,3981],{"class":3980},[3772,27681,27682],{"class":3984}," toggleTripLikeThunk",[3772,27684,3988],{"class":3945},[3772,27686,3853],{"class":3949},[3772,27688,14989],{"class":3945},[3772,27690,27691,27693,27695,27697,27699,27701,27703,27705,27707],{"class":3774,"line":4005},[3772,27692,14994],{"class":3945},[3772,27694,7598],{"class":4719},[3772,27696,4800],{"class":3945},[3772,27698,6459],{"class":3949},[3772,27700,7818],{"class":3945},[3772,27702,14785],{"class":4719},[3772,27704,4800],{"class":3945},[3772,27706,6729],{"class":3949},[3772,27708,4761],{"class":3945},[3772,27710,27711,27713,27715,27717,27719],{"class":3774,"line":4011},[3772,27712,14994],{"class":3945},[3772,27714,7598],{"class":4719},[3772,27716,4800],{"class":3945},[3772,27718,6459],{"class":3949},[3772,27720,4761],{"class":3945},[3772,27722,27723,27725,27727,27729,27731,27733,27735,27737,27739,27741,27743,27745,27748,27750,27752],{"class":3774,"line":4017},[3772,27724,14994],{"class":3945},[3772,27726,5153],{"class":4719},[3772,27728,4800],{"class":3945},[3772,27730,14962],{"class":3949},[3772,27732,7818],{"class":3945},[3772,27734,21999],{"class":4719},[3772,27736,4835],{"class":3945},[3772,27738,7598],{"class":4719},[3772,27740,4800],{"class":3945},[3772,27742,6459],{"class":3949},[3772,27744,7818],{"class":3945},[3772,27746,27747],{"class":4719},"previousLikedState",[3772,27749,4800],{"class":3945},[3772,27751,6729],{"class":3949},[3772,27753,27754],{"class":3945}," } }\n",[3772,27756,27757,27759,27762,27764,27766,27768,27770,27772,27774,27776,27778,27780,27782],{"class":3774,"line":4023},[3772,27758,15076],{"class":3945},[3772,27760,27761],{"class":3781},"'trips\u002FtoggleLike'",[3772,27763,3847],{"class":3945},[3772,27765,15084],{"class":3980},[3772,27767,15087],{"class":3945},[3772,27769,7598],{"class":3949},[3772,27771,15092],{"class":3945},[3772,27773,4062],{"class":3949},[3772,27775,3847],{"class":3945},[3772,27777,15099],{"class":3949},[3772,27779,15102],{"class":3945},[3772,27781,5768],{"class":3980},[3772,27783,4002],{"class":3945},[3772,27785,27786,27788,27791,27793,27795,27797,27799,27801,27803,27805,27807,27809],{"class":3774,"line":4028},[3772,27787,10944],{"class":3980},[3772,27789,27790],{"class":3984}," previousLikedState",[3772,27792,3988],{"class":3945},[3772,27794,4062],{"class":3778},[3772,27796,7205],{"class":3945},[3772,27798,8983],{"class":3949},[3772,27800,4059],{"class":3945},[3772,27802,14645],{"class":3949},[3772,27804,10793],{"class":3945},[3772,27806,7598],{"class":3949},[3772,27808,14652],{"class":3945},[3772,27810,9324],{"class":3980},[3772,27812,27813,27815],{"class":3774,"line":4034},[3772,27814,15147],{"class":3941},[3772,27816,4002],{"class":3945},[3772,27818,27819,27821,27823,27825,27827,27829,27831,27833,27835,27837,27839,27841,27843,27845],{"class":3774,"line":4068},[3772,27820,10557],{"class":3980},[3772,27822,15161],{"class":3984},[3772,27824,3988],{"class":3945},[3772,27826,15166],{"class":3941},[3772,27828,15169],{"class":3949},[3772,27830,4059],{"class":3945},[3772,27832,15174],{"class":3778},[3772,27834,5150],{"class":3945},[3772,27836,15179],{"class":3781},[3772,27838,15182],{"class":3980},[3772,27840,7598],{"class":3949},[3772,27842,4235],{"class":3980},[3772,27844,15189],{"class":3781},[3772,27846,15192],{"class":3945},[3772,27848,27849,27851,27853,27855],{"class":3774,"line":4313},[3772,27850,15197],{"class":3949},[3772,27852,10699],{"class":3945},[3772,27854,27747],{"class":3949},[3772,27856,4806],{"class":3945},[3772,27858,27859],{"class":3774,"line":4470},[3772,27860,14303],{"class":3945},[3772,27862,27863,27865,27867,27869,27871,27874,27876,27878,27880,27882,27884],{"class":3774,"line":4879},[3772,27864,5202],{"class":3941},[3772,27866,3946],{"class":3945},[3772,27868,7598],{"class":3949},[3772,27870,3847],{"class":3945},[3772,27872,27873],{"class":3949},"isLiked:",[3772,27875,15161],{"class":3949},[3772,27877,4059],{"class":3945},[3772,27879,8198],{"class":3949},[3772,27881,4059],{"class":3945},[3772,27883,15245],{"class":3949},[3772,27885,4787],{"class":3945},[3772,27887,27888,27890,27892,27894,27896],{"class":3774,"line":4892},[3772,27889,15256],{"class":3945},[3772,27891,15259],{"class":3941},[3772,27893,5179],{"class":3945},[3772,27895,5072],{"class":3949},[3772,27897,5166],{"class":3945},[3772,27899,27900],{"class":3774,"line":4903},[3772,27901,27902],{"class":3934},"        \u002F\u002F У разі збою повертаємо попередній стан для відкату!\n",[3772,27904,27905,27907,27909,27911,27913,27915,27917],{"class":3774,"line":4909},[3772,27906,5202],{"class":3941},[3772,27908,15277],{"class":3778},[3772,27910,10074],{"class":3945},[3772,27912,7598],{"class":3949},[3772,27914,3847],{"class":3945},[3772,27916,27747],{"class":3949},[3772,27918,24997],{"class":3945},[3772,27920,27921],{"class":3774,"line":5521},[3772,27922,4906],{"class":3945},[3772,27924,27925],{"class":3774,"line":5527},[3772,27926,4020],{"class":3945},[3772,27928,27929],{"class":3774,"line":5533},[3772,27930,3965],{"emptyLinePlaceholder":3964},[3772,27932,27933,27935,27937],{"class":3774,"line":5539},[3772,27934,6376],{"class":3980},[3772,27936,15362],{"class":4042},[3772,27938,4002],{"class":3945},[3772,27940,27941,27943,27945,27947,27949,27951,27953,27955],{"class":3774,"line":5545},[3772,27942,15369],{"class":3949},[3772,27944,4800],{"class":3945},[3772,27946,15374],{"class":4042},[3772,27948,4051],{"class":3945},[3772,27950,6459],{"class":4042},[3772,27952,3847],{"class":3945},[3772,27954,6729],{"class":4042},[3772,27956,4065],{"class":3945},[3772,27958,27959],{"class":3774,"line":5550},[3772,27960,4316],{"class":3945},[3772,27962,27963],{"class":3774,"line":6121},[3772,27964,3965],{"emptyLinePlaceholder":3964},[3772,27966,27967,27969,27971,27973,27975,27977,27980],{"class":3774,"line":6131},[3772,27968,5885],{"class":3980},[3772,27970,5888],{"class":3984},[3772,27972,4800],{"class":3945},[3772,27974,15427],{"class":4042},[3772,27976,7352],{"class":3945},[3772,27978,27979],{"class":3949},"byTripId:",[3772,27981,27982],{"class":3945}," {} }\n",[3772,27984,27985],{"class":3774,"line":6136},[3772,27986,3965],{"emptyLinePlaceholder":3964},[3772,27988,27989,27991,27993,27995,27997,27999],{"class":3774,"line":6142},[3772,27990,3977],{"class":3941},[3772,27992,3981],{"class":3980},[3772,27994,15469],{"class":3984},[3772,27996,3988],{"class":3945},[3772,27998,3846],{"class":3778},[3772,28000,3993],{"class":3945},[3772,28002,28003,28005,28007],{"class":3774,"line":6150},[3772,28004,6540],{"class":3949},[3772,28006,15482],{"class":3781},[3772,28008,4806],{"class":3945},[3772,28010,28011,28013],{"class":3774,"line":6157},[3772,28012,6550],{"class":3949},[3772,28014,4806],{"class":3945},[3772,28016,28017,28019],{"class":3774,"line":6162},[3772,28018,6557],{"class":3949},[3772,28020,12632],{"class":3945},[3772,28022,28023,28025,28027,28029,28031,28033,28035],{"class":3774,"line":6629},[3772,28024,9190],{"class":3778},[3772,28026,4094],{"class":3949},[3772,28028,5179],{"class":3945},[3772,28030,9197],{"class":3949},[3772,28032,5765],{"class":3945},[3772,28034,5768],{"class":3980},[3772,28036,4002],{"class":3945},[3772,28038,28039],{"class":3774,"line":6653},[3772,28040,9215],{"class":3949},[3772,28042,28043],{"class":3774,"line":6698},[3772,28044,28045],{"class":3934},"            \u002F\u002F 1. ОПТИМІСТИЧНЕ ОНОВЛЕННЯ: Миттєво змінюємо UI при pending!\n",[3772,28047,28048,28050,28052,28054,28057,28059,28061,28063,28065,28067,28069,28071,28073],{"class":3774,"line":6703},[3772,28049,9221],{"class":3945},[3772,28051,9224],{"class":3778},[3772,28053,5150],{"class":3945},[3772,28055,28056],{"class":3949},"toggleTripLikeThunk",[3772,28058,4059],{"class":3945},[3772,28060,9234],{"class":3949},[3772,28062,7128],{"class":3945},[3772,28064,5153],{"class":3949},[3772,28066,3847],{"class":3945},[3772,28068,5163],{"class":3949},[3772,28070,5765],{"class":3945},[3772,28072,5768],{"class":3980},[3772,28074,4002],{"class":3945},[3772,28076,28077,28079,28081,28083,28085,28087,28089,28091,28093],{"class":3774,"line":6709},[3772,28078,15563],{"class":3980},[3772,28080,3946],{"class":3945},[3772,28082,7598],{"class":3984},[3772,28084,6801],{"class":3945},[3772,28086,5163],{"class":3949},[3772,28088,4059],{"class":3945},[3772,28090,5067],{"class":3949},[3772,28092,4059],{"class":3945},[3772,28094,15580],{"class":3949},[3772,28096,28097,28099,28102,28104,28106,28108,28110,28112,28114,28116],{"class":3774,"line":6734},[3772,28098,15563],{"class":3980},[3772,28100,28101],{"class":3984}," current",[3772,28103,3988],{"class":3945},[3772,28105,5153],{"class":3949},[3772,28107,4059],{"class":3945},[3772,28109,14645],{"class":3949},[3772,28111,10793],{"class":3945},[3772,28113,7598],{"class":3949},[3772,28115,14652],{"class":3945},[3772,28117,9324],{"class":3980},[3772,28119,28120,28122,28124,28126,28128,28130,28132],{"class":3774,"line":6753},[3772,28121,8815],{"class":3949},[3772,28123,4059],{"class":3945},[3772,28125,14645],{"class":3949},[3772,28127,10793],{"class":3945},[3772,28129,7598],{"class":3949},[3772,28131,15627],{"class":3945},[3772,28133,28134],{"class":3949},"current\n",[3772,28136,28137],{"class":3774,"line":6758},[3772,28138,9263],{"class":3945},[3772,28140,28141],{"class":3774,"line":6763},[3772,28142,28143],{"class":3934},"            \u002F\u002F 2. У разі успіху фіксуємо точну відповідь сервера\n",[3772,28145,28146,28148,28150,28152,28154,28156,28158,28160,28162,28164,28166,28168,28170],{"class":3774,"line":6768},[3772,28147,9221],{"class":3945},[3772,28149,9224],{"class":3778},[3772,28151,5150],{"class":3945},[3772,28153,28056],{"class":3949},[3772,28155,4059],{"class":3945},[3772,28157,9279],{"class":3949},[3772,28159,7128],{"class":3945},[3772,28161,5153],{"class":3949},[3772,28163,3847],{"class":3945},[3772,28165,5163],{"class":3949},[3772,28167,5765],{"class":3945},[3772,28169,5768],{"class":3980},[3772,28171,4002],{"class":3945},[3772,28173,28174,28176,28178,28180,28182,28184,28186,28188,28190,28192,28194,28196,28198,28200,28202],{"class":3774,"line":6773},[3772,28175,8815],{"class":3949},[3772,28177,4059],{"class":3945},[3772,28179,14645],{"class":3949},[3772,28181,10793],{"class":3945},[3772,28183,5163],{"class":3949},[3772,28185,4059],{"class":3945},[3772,28187,5059],{"class":3949},[3772,28189,4059],{"class":3945},[3772,28191,7598],{"class":3949},[3772,28193,10798],{"class":3945},[3772,28195,5163],{"class":3949},[3772,28197,4059],{"class":3945},[3772,28199,5059],{"class":3949},[3772,28201,4059],{"class":3945},[3772,28203,15761],{"class":3949},[3772,28205,28206],{"class":3774,"line":6779},[3772,28207,9263],{"class":3945},[3772,28209,28210],{"class":3774,"line":6812},[3772,28211,28212],{"class":3934},"            \u002F\u002F 3. ВІДКАТ (ROLLBACK): Повертаємо попереднє значення при помилці\n",[3772,28214,28215,28217,28219,28221,28223,28225,28227,28229,28231,28233,28235,28237,28239],{"class":3774,"line":6817},[3772,28216,9221],{"class":3945},[3772,28218,9224],{"class":3778},[3772,28220,5150],{"class":3945},[3772,28222,28056],{"class":3949},[3772,28224,4059],{"class":3945},[3772,28226,12260],{"class":3949},[3772,28228,7128],{"class":3945},[3772,28230,5153],{"class":3949},[3772,28232,3847],{"class":3945},[3772,28234,5163],{"class":3949},[3772,28236,5765],{"class":3945},[3772,28238,5768],{"class":3980},[3772,28240,4002],{"class":3945},[3772,28242,28243,28245,28247,28249,28251,28253],{"class":3774,"line":6823},[3772,28244,15842],{"class":3941},[3772,28246,5179],{"class":3945},[3772,28248,5163],{"class":3949},[3772,28250,4059],{"class":3945},[3772,28252,5059],{"class":3949},[3772,28254,5166],{"class":3945},[3772,28256,28257,28259,28261,28263,28265,28267,28269,28271,28273,28275,28277,28279,28281,28283,28285],{"class":3774,"line":8841},[3772,28258,12978],{"class":3949},[3772,28260,4059],{"class":3945},[3772,28262,14645],{"class":3949},[3772,28264,10793],{"class":3945},[3772,28266,5163],{"class":3949},[3772,28268,4059],{"class":3945},[3772,28270,5059],{"class":3949},[3772,28272,4059],{"class":3945},[3772,28274,7598],{"class":3949},[3772,28276,10798],{"class":3945},[3772,28278,5163],{"class":3949},[3772,28280,4059],{"class":3945},[3772,28282,5059],{"class":3949},[3772,28284,4059],{"class":3945},[3772,28286,28287],{"class":3949},"previousLikedState\n",[3772,28289,28290],{"class":3774,"line":8865},[3772,28291,8931],{"class":3945},[3772,28293,28294],{"class":3774,"line":8873},[3772,28295,9263],{"class":3945},[3772,28297,28298],{"class":3774,"line":8881},[3772,28299,4014],{"class":3945},[3772,28301,28302],{"class":3774,"line":8894},[3772,28303,4020],{"class":3945},[4495,28305],{},[3738,28307,28309],{"id":28308},"серіалізованість-даних-чому-це-критично","Серіалізованість даних: чому це критично",[3743,28311,28312,28313,28316,28317,28320],{},"Одна з найважливіших вимог Redux — ",[3829,28314,28315],{},"серіалізованість стану",". Це означає, що будь-які дані в store мають бути представлені у вигляді простих JavaScript-значень: рядків, чисел, булевих прапорців, масивів та простих об'єктів (",[4508,28318,28319],{},"Plain Old JavaScript Objects","). Значення має бути можливим перетворити в рядок JSON і розпарсити назад без втрати інформації та методів.",[3747,28322,28324],{"id":28323},"що-категорично-заборонено-зберігати-в-redux-store","Що категорично заборонено зберігати в Redux store",[28326,28327,28328,28333],"caution",{},[3743,28329,28330],{},[3829,28331,28332],{},"Заборонені типи даних у Redux store:",[4588,28334,28335,28344,28361,28373,28396],{},[3836,28336,28337,5572,28340,28343],{},[3829,28338,28339],{},"Функції та методи",[3769,28341,28342],{},"(x) => x * 2"," неможливо серіалізувати в JSON.",[3836,28345,28346,5572,28349,3847,28351,3847,28354,3847,28357,28360],{},[3829,28347,28348],{},"Екземпляри класів",[3769,28350,7457],{},[3769,28352,28353],{},"new Map()",[3769,28355,28356],{},"new Set()",[3769,28358,28359],{},"new RegExp()"," та користувацькі класи. При серіалізації в JSON втрачаються методи, прототипи та спеціальні внутрішні слоти.",[3836,28362,28363,5572,28366,28369,28370,4059],{},[3829,28364,28365],{},"Символи (Symbols)",[3769,28367,28368],{},"Symbol('id')"," відкидається при серіалізації ",[3769,28371,28372],{},"JSON.stringify",[3836,28374,28375,28378,28379,28382,28383,28386,28387,28389,28390,28392,28393,4059],{},[3829,28376,28377],{},"Циклічні посилання"," — коли об'єкт ",[7424,28380],{":inline":19258,"tex":28381},"A"," посилається на об'єкт ",[7424,28384],{":inline":19258,"tex":28385},"B",", який посилається назад на ",[7424,28388],{":inline":19258,"tex":28381},". Виклик ",[3769,28391,28372],{}," впаде з помилкою ",[3769,28394,28395],{},"TypeError: Converting circular structure to JSON",[3836,28397,28398,28401],{},[3829,28399,28400],{},"Нативні дескриптори та посилання"," — посилання на елементи інтерфейсу, нативні сокети або файлові потоки.",[3747,28403,28405],{"id":28404},"чому-серіалізованість-критична-для-мобільних-застосунків","Чому серіалізованість критична для мобільних застосунків?",[4588,28407,28408,28420,28426],{},[3836,28409,28410,28413,28414,28416,28417,4059],{},[3829,28411,28412],{},"Персистентність та відновлення сесії (Rehydration):","\nПри згортанні застосунку операційна система може вивантажити процес із пам'яті. Щоб користувач не втратив дані, стан Redux серіалізується в JSON і записується в постійну пам'ять пристрою (AsyncStorage, MMKV або SQLite). Якщо в store знаходився екземпляр класу ",[3769,28415,13933],{},", після відновлення ви отримаєте звичайний рядок, що призведе до помилок на кшталт ",[3769,28418,28419],{},"trip.startDate.getFullYear is not a function",[3836,28421,28422,28425],{},[3829,28423,28424],{},"Time-Travel Debugging у Redux DevTools:","\nDevTools створює знімки дій і стану у форматі JSON. Несеріалізовані об'єкти ламають функціонал перемотування та експорту\u002Fімпорту стану.",[3836,28427,28428,28431,28432,28435],{},[3829,28429,28430],{},"Чистота тестування:","\nПрості серіалізовані структури можна порівнювати через ",[3769,28433,28434],{},"toEqual",", легко мокати у юніт-тестах без необхідності створювати екземпляри складних класів.",[3747,28437,28439],{"id":28438},"як-правильно-зберігати-дати-та-складні-типи","Як правильно зберігати дати та складні типи",[3743,28441,28442],{},"Подивимося на порівняння правильного та помилкового підходів:",[3755,28444,28445,28554,28716],{},[3758,28446,28448],{"label":28447},"Погано ❌ (Несеріалізований об'єкт Date)",[3762,28449,28451],{"className":3925,"code":28450,"language":3927,"meta":3767,"style":3767},"\u002F\u002F НЕКОРЕКТНО: збереження екземпляра Date\ninterface TripState {\n    id: string\n    title: string\n    startDate: Date \u002F\u002F ❌ Порушення серіалізованості!\n}\n\nconst trip: TripState = {\n    id: '1',\n    title: 'Похід на Говерлу',\n    startDate: new Date('2026-08-11T10:00:00.000Z'),\n}\n",[3769,28452,28453,28458,28467,28475,28483,28494,28498,28502,28515,28524,28534,28550],{"__ignoreMap":3767},[3772,28454,28455],{"class":3774,"line":3775},[3772,28456,28457],{"class":3934},"\u002F\u002F НЕКОРЕКТНО: збереження екземпляра Date\n",[3772,28459,28460,28462,28465],{"class":3774,"line":3938},[3772,28461,6376],{"class":3980},[3772,28463,28464],{"class":4042}," TripState",[3772,28466,4002],{"class":3945},[3772,28468,28469,28471,28473],{"class":3774,"line":3961},[3772,28470,6386],{"class":3949},[3772,28472,4800],{"class":3945},[3772,28474,6391],{"class":4042},[3772,28476,28477,28479,28481],{"class":3774,"line":3968},[3772,28478,6396],{"class":3949},[3772,28480,4800],{"class":3945},[3772,28482,6391],{"class":4042},[3772,28484,28485,28487,28489,28491],{"class":3774,"line":3974},[3772,28486,22500],{"class":3949},[3772,28488,4800],{"class":3945},[3772,28490,13933],{"class":4042},[3772,28492,28493],{"class":3934}," \u002F\u002F ❌ Порушення серіалізованості!\n",[3772,28495,28496],{"class":3774,"line":3996},[3772,28497,4316],{"class":3945},[3772,28499,28500],{"class":3774,"line":4005},[3772,28501,3965],{"emptyLinePlaceholder":3964},[3772,28503,28504,28506,28508,28510,28513],{"class":3774,"line":4011},[3772,28505,5885],{"class":3980},[3772,28507,5788],{"class":3984},[3772,28509,4800],{"class":3945},[3772,28511,28512],{"class":4042},"TripState",[3772,28514,5891],{"class":3945},[3772,28516,28517,28520,28522],{"class":3774,"line":4017},[3772,28518,28519],{"class":3949},"    id:",[3772,28521,4742],{"class":3781},[3772,28523,4806],{"class":3945},[3772,28525,28526,28529,28532],{"class":3774,"line":4023},[3772,28527,28528],{"class":3949},"    title:",[3772,28530,28531],{"class":3781}," 'Похід на Говерлу'",[3772,28533,4806],{"class":3945},[3772,28535,28536,28539,28541,28543,28545,28548],{"class":3774,"line":4028},[3772,28537,28538],{"class":3949},"    startDate:",[3772,28540,7199],{"class":3980},[3772,28542,7202],{"class":3778},[3772,28544,5150],{"class":3945},[3772,28546,28547],{"class":3781},"'2026-08-11T10:00:00.000Z'",[3772,28549,6082],{"class":3945},[3772,28551,28552],{"class":3774,"line":4034},[3772,28553,4316],{"class":3945},[3758,28555,28557],{"label":28556},"Добре ✅ (ISO 8601 рядок)",[3762,28558,28560],{"className":3925,"code":28559,"language":3927,"meta":3767,"style":3767},"\u002F\u002F РЕКОМЕНДОВАНО: ISO 8601 рядок або Unix timestamp\ninterface TripState {\n    id: string\n    title: string\n    startDate: string \u002F\u002F ✅ Серіалізований ISO-рядок: \"2026-08-11T10:00:00.000Z\"\n    createdAtTimestamp: number \u002F\u002F ✅ Серіалізований Unix timestamp: 1754985600000\n}\n\nconst trip: TripState = {\n    id: '1',\n    title: 'Похід на Говерлу',\n    startDate: '2026-08-11T10:00:00.000Z',\n    createdAtTimestamp: 1754985600000,\n}\n\n\u002F\u002F Перетворення на Date виконується локально в компоненті або селекторі:\nconst formattedDate = new Date(trip.startDate).toLocaleDateString('uk-UA')\n",[3769,28561,28562,28567,28575,28583,28591,28602,28614,28618,28622,28634,28642,28650,28659,28669,28673,28677,28682],{"__ignoreMap":3767},[3772,28563,28564],{"class":3774,"line":3775},[3772,28565,28566],{"class":3934},"\u002F\u002F РЕКОМЕНДОВАНО: ISO 8601 рядок або Unix timestamp\n",[3772,28568,28569,28571,28573],{"class":3774,"line":3938},[3772,28570,6376],{"class":3980},[3772,28572,28464],{"class":4042},[3772,28574,4002],{"class":3945},[3772,28576,28577,28579,28581],{"class":3774,"line":3961},[3772,28578,6386],{"class":3949},[3772,28580,4800],{"class":3945},[3772,28582,6391],{"class":4042},[3772,28584,28585,28587,28589],{"class":3774,"line":3968},[3772,28586,6396],{"class":3949},[3772,28588,4800],{"class":3945},[3772,28590,6391],{"class":4042},[3772,28592,28593,28595,28597,28599],{"class":3774,"line":3974},[3772,28594,22500],{"class":3949},[3772,28596,4800],{"class":3945},[3772,28598,6459],{"class":4042},[3772,28600,28601],{"class":3934}," \u002F\u002F ✅ Серіалізований ISO-рядок: \"2026-08-11T10:00:00.000Z\"\n",[3772,28603,28604,28607,28609,28611],{"class":3774,"line":3996},[3772,28605,28606],{"class":3949},"    createdAtTimestamp",[3772,28608,4800],{"class":3945},[3772,28610,7833],{"class":4042},[3772,28612,28613],{"class":3934}," \u002F\u002F ✅ Серіалізований Unix timestamp: 1754985600000\n",[3772,28615,28616],{"class":3774,"line":4005},[3772,28617,4316],{"class":3945},[3772,28619,28620],{"class":3774,"line":4011},[3772,28621,3965],{"emptyLinePlaceholder":3964},[3772,28623,28624,28626,28628,28630,28632],{"class":3774,"line":4017},[3772,28625,5885],{"class":3980},[3772,28627,5788],{"class":3984},[3772,28629,4800],{"class":3945},[3772,28631,28512],{"class":4042},[3772,28633,5891],{"class":3945},[3772,28635,28636,28638,28640],{"class":3774,"line":4023},[3772,28637,28519],{"class":3949},[3772,28639,4742],{"class":3781},[3772,28641,4806],{"class":3945},[3772,28643,28644,28646,28648],{"class":3774,"line":4028},[3772,28645,28528],{"class":3949},[3772,28647,28531],{"class":3781},[3772,28649,4806],{"class":3945},[3772,28651,28652,28654,28657],{"class":3774,"line":4034},[3772,28653,28538],{"class":3949},[3772,28655,28656],{"class":3781}," '2026-08-11T10:00:00.000Z'",[3772,28658,4806],{"class":3945},[3772,28660,28661,28664,28667],{"class":3774,"line":4068},[3772,28662,28663],{"class":3949},"    createdAtTimestamp:",[3772,28665,28666],{"class":8916}," 1754985600000",[3772,28668,4806],{"class":3945},[3772,28670,28671],{"class":3774,"line":4313},[3772,28672,4316],{"class":3945},[3772,28674,28675],{"class":3774,"line":4470},[3772,28676,3965],{"emptyLinePlaceholder":3964},[3772,28678,28679],{"class":3774,"line":4879},[3772,28680,28681],{"class":3934},"\u002F\u002F Перетворення на Date виконується локально в компоненті або селекторі:\n",[3772,28683,28684,28686,28689,28691,28693,28695,28697,28699,28701,28704,28706,28709,28711,28714],{"class":3774,"line":4892},[3772,28685,5885],{"class":3980},[3772,28687,28688],{"class":3984}," formattedDate",[3772,28690,3988],{"class":3945},[3772,28692,22061],{"class":3980},[3772,28694,7202],{"class":3778},[3772,28696,5150],{"class":3945},[3772,28698,5762],{"class":3949},[3772,28700,4059],{"class":3945},[3772,28702,28703],{"class":3949},"startDate",[3772,28705,7467],{"class":3945},[3772,28707,28708],{"class":3778},"toLocaleDateString",[3772,28710,5150],{"class":3945},[3772,28712,28713],{"class":3781},"'uk-UA'",[3772,28715,5345],{"class":3945},[3758,28717,28719],{"label":28718},"Добре ✅ (Заміна Map та Set)",[3762,28720,28722],{"className":3925,"code":28721,"language":3927,"meta":3767,"style":3767},"\u002F\u002F Замість Map\u003Cstring, Trip> використовуйте звичайний Record\u003Cstring, Trip>\ninterface NormalizedTripsState {\n    byId: Record\u003Cstring, Trip> \u002F\u002F ✅ Серіалізований словник\n    allIds: string[] \u002F\u002F ✅ Замість Set\u003Cstring> використовуємо масив унікальних ID\n}\n",[3769,28723,28724,28729,28738,28760,28775],{"__ignoreMap":3767},[3772,28725,28726],{"class":3774,"line":3775},[3772,28727,28728],{"class":3934},"\u002F\u002F Замість Map\u003Cstring, Trip> використовуйте звичайний Record\u003Cstring, Trip>\n",[3772,28730,28731,28733,28736],{"class":3774,"line":3938},[3772,28732,6376],{"class":3980},[3772,28734,28735],{"class":4042}," NormalizedTripsState",[3772,28737,4002],{"class":3945},[3772,28739,28740,28743,28745,28747,28749,28751,28753,28755,28757],{"class":3774,"line":3961},[3772,28741,28742],{"class":3949},"    byId",[3772,28744,4800],{"class":3945},[3772,28746,15374],{"class":4042},[3772,28748,4051],{"class":3945},[3772,28750,6459],{"class":4042},[3772,28752,3847],{"class":3945},[3772,28754,6436],{"class":4042},[3772,28756,15385],{"class":3945},[3772,28758,28759],{"class":3934},"\u002F\u002F ✅ Серіалізований словник\n",[3772,28761,28762,28765,28767,28769,28772],{"class":3774,"line":3968},[3772,28763,28764],{"class":3949},"    allIds",[3772,28766,4800],{"class":3945},[3772,28768,6459],{"class":4042},[3772,28770,28771],{"class":3945},"[] ",[3772,28773,28774],{"class":3934},"\u002F\u002F ✅ Замість Set\u003Cstring> використовуємо масив унікальних ID\n",[3772,28776,28777],{"class":3774,"line":3974},[3772,28778,4316],{"class":3945},[4495,28780],{},[3738,28782,28784],{"id":28783},"тестування-redux-логіки-у-react-native","Тестування Redux логіки у React Native",[3743,28786,28787],{},"Оскільки редюсери та селектори є чистими функціями, їх тестування виконується блискавично без монтування важких компонентів React:",[3762,28789,28791],{"className":3925,"code":28790,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002F__tests__\u002FtripsSlice.test.ts\nimport tripsReducer, { addTrip, clearTripsError } from '..\u002FtripsSlice'\n\ndescribe('tripsSlice Reducer', () => {\n    const initialState = {\n        items: [{ id: '1', title: 'Київ', region: 'Центр' }],\n        loading: false,\n        error: 'Попередня помилка',\n    }\n\n    it('повинен додавати нову поїздку на початок списку через addTrip', () => {\n        const newTrip = { id: '2', title: 'Одеса', region: 'Південь' }\n        const nextState = tripsReducer(initialState as any, addTrip(newTrip as any))\n\n        expect(nextState.items).toHaveLength(2)\n        expect(nextState.items[0]).toEqual(newTrip)\n    })\n\n    it('повинен очищувати помилку через clearTripsError', () => {\n        const nextState = tripsReducer(initialState as any, clearTripsError())\n        expect(nextState.error).toBeNull()\n    })\n})\n",[3769,28792,28793,28798,28820,28824,28841,28849,28877,28885,28895,28899,28903,28919,28946,28980,28984,29010,29038,29042,29046,29061,29085,29104,29108],{"__ignoreMap":3767},[3772,28794,28795],{"class":3774,"line":3775},[3772,28796,28797],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fslices\u002F__tests__\u002FtripsSlice.test.ts\n",[3772,28799,28800,28802,28804,28806,28808,28810,28813,28815,28817],{"class":3774,"line":3938},[3772,28801,3942],{"class":3941},[3772,28803,5147],{"class":3949},[3772,28805,20886],{"class":3945},[3772,28807,6788],{"class":3949},[3772,28809,3847],{"class":3945},[3772,28811,28812],{"class":3949},"clearTripsError",[3772,28814,3952],{"class":3945},[3772,28816,3955],{"class":3941},[3772,28818,28819],{"class":3781}," '..\u002FtripsSlice'\n",[3772,28821,28822],{"class":3774,"line":3961},[3772,28823,3965],{"emptyLinePlaceholder":3964},[3772,28825,28826,28829,28831,28834,28837,28839],{"class":3774,"line":3968},[3772,28827,28828],{"class":3778},"describe",[3772,28830,5150],{"class":3945},[3772,28832,28833],{"class":3781},"'tripsSlice Reducer'",[3772,28835,28836],{"class":3945},", () ",[3772,28838,5768],{"class":3980},[3772,28840,4002],{"class":3945},[3772,28842,28843,28845,28847],{"class":3774,"line":3974},[3772,28844,10944],{"class":3980},[3772,28846,5888],{"class":3984},[3772,28848,5891],{"class":3945},[3772,28850,28851,28854,28857,28859,28861,28863,28865,28867,28869,28871,28874],{"class":3774,"line":3996},[3772,28852,28853],{"class":3949},"        items:",[3772,28855,28856],{"class":3945}," [{ ",[3772,28858,4739],{"class":3949},[3772,28860,4742],{"class":3781},[3772,28862,3847],{"class":3945},[3772,28864,4747],{"class":3949},[3772,28866,10085],{"class":3781},[3772,28868,3847],{"class":3945},[3772,28870,4755],{"class":3949},[3772,28872,28873],{"class":3781}," 'Центр'",[3772,28875,28876],{"class":3945}," }],\n",[3772,28878,28879,28881,28883],{"class":3774,"line":4005},[3772,28880,11443],{"class":3949},[3772,28882,4279],{"class":3980},[3772,28884,4806],{"class":3945},[3772,28886,28887,28890,28893],{"class":3774,"line":4011},[3772,28888,28889],{"class":3949},"        error:",[3772,28891,28892],{"class":3781}," 'Попередня помилка'",[3772,28894,4806],{"class":3945},[3772,28896,28897],{"class":3774,"line":4017},[3772,28898,4906],{"class":3945},[3772,28900,28901],{"class":3774,"line":4023},[3772,28902,3965],{"emptyLinePlaceholder":3964},[3772,28904,28905,28908,28910,28913,28915,28917],{"class":3774,"line":4028},[3772,28906,28907],{"class":3778},"    it",[3772,28909,5150],{"class":3945},[3772,28911,28912],{"class":3781},"'повинен додавати нову поїздку на початок списку через addTrip'",[3772,28914,28836],{"class":3945},[3772,28916,5768],{"class":3980},[3772,28918,4002],{"class":3945},[3772,28920,28921,28923,28926,28928,28930,28932,28934,28936,28938,28940,28942,28944],{"class":3774,"line":4034},[3772,28922,10557],{"class":3980},[3772,28924,28925],{"class":3984}," newTrip",[3772,28927,7352],{"class":3945},[3772,28929,4739],{"class":3949},[3772,28931,4770],{"class":3781},[3772,28933,3847],{"class":3945},[3772,28935,4747],{"class":3949},[3772,28937,4777],{"class":3781},[3772,28939,3847],{"class":3945},[3772,28941,4755],{"class":3949},[3772,28943,4784],{"class":3781},[3772,28945,4787],{"class":3945},[3772,28947,28948,28950,28953,28955,28957,28959,28961,28963,28966,28968,28970,28972,28974,28976,28978],{"class":3774,"line":4068},[3772,28949,10557],{"class":3980},[3772,28951,28952],{"class":3984}," nextState",[3772,28954,3988],{"class":3945},[3772,28956,6239],{"class":3778},[3772,28958,5150],{"class":3945},[3772,28960,5158],{"class":3949},[3772,28962,13221],{"class":3941},[3772,28964,28965],{"class":4042}," any",[3772,28967,3847],{"class":3945},[3772,28969,6788],{"class":3778},[3772,28971,5150],{"class":3945},[3772,28973,10983],{"class":3949},[3772,28975,13221],{"class":3941},[3772,28977,28965],{"class":4042},[3772,28979,10331],{"class":3945},[3772,28981,28982],{"class":3774,"line":4313},[3772,28983,3965],{"emptyLinePlaceholder":3964},[3772,28985,28986,28989,28991,28994,28996,28998,29000,29003,29005,29008],{"class":3774,"line":4470},[3772,28987,28988],{"class":3778},"        expect",[3772,28990,5150],{"class":3945},[3772,28992,28993],{"class":3949},"nextState",[3772,28995,4059],{"class":3945},[3772,28997,5237],{"class":3949},[3772,28999,7467],{"class":3945},[3772,29001,29002],{"class":3778},"toHaveLength",[3772,29004,5150],{"class":3945},[3772,29006,29007],{"class":8916},"2",[3772,29009,5345],{"class":3945},[3772,29011,29012,29014,29016,29018,29020,29022,29024,29027,29030,29032,29034,29036],{"class":3774,"line":4879},[3772,29013,28988],{"class":3778},[3772,29015,5150],{"class":3945},[3772,29017,28993],{"class":3949},[3772,29019,4059],{"class":3945},[3772,29021,5237],{"class":3949},[3772,29023,10793],{"class":3945},[3772,29025,29026],{"class":8916},"0",[3772,29028,29029],{"class":3945},"]).",[3772,29031,28434],{"class":3778},[3772,29033,5150],{"class":3945},[3772,29035,10983],{"class":3949},[3772,29037,5345],{"class":3945},[3772,29039,29040],{"class":3774,"line":4892},[3772,29041,13379],{"class":3945},[3772,29043,29044],{"class":3774,"line":4903},[3772,29045,3965],{"emptyLinePlaceholder":3964},[3772,29047,29048,29050,29052,29055,29057,29059],{"class":3774,"line":4909},[3772,29049,28907],{"class":3778},[3772,29051,5150],{"class":3945},[3772,29053,29054],{"class":3781},"'повинен очищувати помилку через clearTripsError'",[3772,29056,28836],{"class":3945},[3772,29058,5768],{"class":3980},[3772,29060,4002],{"class":3945},[3772,29062,29063,29065,29067,29069,29071,29073,29075,29077,29079,29081,29083],{"class":3774,"line":5521},[3772,29064,10557],{"class":3980},[3772,29066,28952],{"class":3984},[3772,29068,3988],{"class":3945},[3772,29070,6239],{"class":3778},[3772,29072,5150],{"class":3945},[3772,29074,5158],{"class":3949},[3772,29076,13221],{"class":3941},[3772,29078,28965],{"class":4042},[3772,29080,3847],{"class":3945},[3772,29082,28812],{"class":3778},[3772,29084,17271],{"class":3945},[3772,29086,29087,29089,29091,29093,29095,29097,29099,29102],{"class":3774,"line":5527},[3772,29088,28988],{"class":3778},[3772,29090,5150],{"class":3945},[3772,29092,28993],{"class":3949},[3772,29094,4059],{"class":3945},[3772,29096,5072],{"class":3949},[3772,29098,7467],{"class":3945},[3772,29100,29101],{"class":3778},"toBeNull",[3772,29103,13941],{"class":3945},[3772,29105,29106],{"class":3774,"line":5533},[3772,29107,13379],{"class":3945},[3772,29109,29110],{"class":3774,"line":5539},[3772,29111,4020],{"class":3945},[4495,29113],{},[3738,29115,29117],{"id":29116},"повний-цикл-потоку-даних-у-redux-toolkit","Повний цикл потоку даних у Redux Toolkit",[5417,29119,29120],{},[3762,29121,29123],{"className":5422,"code":29122,"language":5424,"meta":3767,"style":3767},"@startuml\nskinparam backgroundColor #ffffff\nskinparam defaultFontName Arial\nskinparam defaultFontSize 12\n\nactor \"Користувач\" as User #bfdbfe\nparticipant \"UI Компонент\\n(useAppDispatch)\" as Component #fef08a\nparticipant \"Store Middleware\\n(Analytics \u002F Thunk)\" as Middleware #fed7aa\nparticipant \"Slice Reducer\\n(Immer Proxy Engine)\" as Reducer #bbf7d0\ndatabase \"Redux Store\\n(Single State Tree)\" as Store #e2e8f0\nparticipant \"Мемоїзований Selector\\n(createSelector)\" as Selector #fed7aa\n\nUser -> Component : 1. Натискання \"Створити поїздку\"\nComponent -> Middleware : 2. dispatch(addTrip({ id, title }))\nMiddleware -> Middleware : 3. Перевірка серіалізованості та логування\nMiddleware -> Reducer : 4. Передача дії у tripsSlice.reducer\n\nReducer -> Reducer : 5. state.list.unshift(payload)\\n(Immer фіксує патчі)\nReducer -> Store : 6. Запис нового імутабельного стану\nStore -> Selector : 7. Сповіщення підписників через subscribe()\n\nSelector -> Selector : 8. Перевірка чи змінилися вхідні посилання\nSelector -> Component : 9. Повернення закешованого або нового результату\nComponent -> User : 10. Миттєвий ререндер зміненої картки на екрані\n@enduml\n",[3769,29124,29125,29129,29133,29138,29142,29146,29151,29156,29161,29166,29171,29176,29180,29185,29190,29195,29200,29204,29209,29214,29219,29223,29228,29233,29238],{"__ignoreMap":3767},[3772,29126,29127],{"class":3774,"line":3775},[3772,29128,5431],{},[3772,29130,29131],{"class":3774,"line":3938},[3772,29132,5441],{},[3772,29134,29135],{"class":3774,"line":3961},[3772,29136,29137],{},"skinparam defaultFontName Arial\n",[3772,29139,29140],{"class":3774,"line":3968},[3772,29141,8005],{},[3772,29143,29144],{"class":3774,"line":3974},[3772,29145,3965],{"emptyLinePlaceholder":3964},[3772,29147,29148],{"class":3774,"line":3996},[3772,29149,29150],{},"actor \"Користувач\" as User #bfdbfe\n",[3772,29152,29153],{"class":3774,"line":4005},[3772,29154,29155],{},"participant \"UI Компонент\\n(useAppDispatch)\" as Component #fef08a\n",[3772,29157,29158],{"class":3774,"line":4011},[3772,29159,29160],{},"participant \"Store Middleware\\n(Analytics \u002F Thunk)\" as Middleware #fed7aa\n",[3772,29162,29163],{"class":3774,"line":4017},[3772,29164,29165],{},"participant \"Slice Reducer\\n(Immer Proxy Engine)\" as Reducer #bbf7d0\n",[3772,29167,29168],{"class":3774,"line":4023},[3772,29169,29170],{},"database \"Redux Store\\n(Single State Tree)\" as Store #e2e8f0\n",[3772,29172,29173],{"class":3774,"line":4028},[3772,29174,29175],{},"participant \"Мемоїзований Selector\\n(createSelector)\" as Selector #fed7aa\n",[3772,29177,29178],{"class":3774,"line":4034},[3772,29179,3965],{"emptyLinePlaceholder":3964},[3772,29181,29182],{"class":3774,"line":4068},[3772,29183,29184],{},"User -> Component : 1. Натискання \"Створити поїздку\"\n",[3772,29186,29187],{"class":3774,"line":4313},[3772,29188,29189],{},"Component -> Middleware : 2. dispatch(addTrip({ id, title }))\n",[3772,29191,29192],{"class":3774,"line":4470},[3772,29193,29194],{},"Middleware -> Middleware : 3. Перевірка серіалізованості та логування\n",[3772,29196,29197],{"class":3774,"line":4879},[3772,29198,29199],{},"Middleware -> Reducer : 4. Передача дії у tripsSlice.reducer\n",[3772,29201,29202],{"class":3774,"line":4892},[3772,29203,3965],{"emptyLinePlaceholder":3964},[3772,29205,29206],{"class":3774,"line":4903},[3772,29207,29208],{},"Reducer -> Reducer : 5. state.list.unshift(payload)\\n(Immer фіксує патчі)\n",[3772,29210,29211],{"class":3774,"line":4909},[3772,29212,29213],{},"Reducer -> Store : 6. Запис нового імутабельного стану\n",[3772,29215,29216],{"class":3774,"line":5521},[3772,29217,29218],{},"Store -> Selector : 7. Сповіщення підписників через subscribe()\n",[3772,29220,29221],{"class":3774,"line":5527},[3772,29222,3965],{"emptyLinePlaceholder":3964},[3772,29224,29225],{"class":3774,"line":5533},[3772,29226,29227],{},"Selector -> Selector : 8. Перевірка чи змінилися вхідні посилання\n",[3772,29229,29230],{"class":3774,"line":5539},[3772,29231,29232],{},"Selector -> Component : 9. Повернення закешованого або нового результату\n",[3772,29234,29235],{"class":3774,"line":5545},[3772,29236,29237],{},"Component -> User : 10. Миттєвий ререндер зміненої картки на екрані\n",[3772,29239,29240],{"class":3774,"line":5550},[3772,29241,5553],{},[4495,29243],{},[3738,29245,29247],{"id":29246},"міні-проєкт-керування-налаштуваннями-та-профілем-з-redux-toolkit","Міні-проєкт: «Керування налаштуваннями та профілем» з Redux Toolkit",[3743,29249,29250],{},"Побудуємо повнофункціональний окремий застосунок, де продемонструємо:",[3833,29252,29253,29260,29267],{},[3836,29254,29255,29256,3869,29258,7445],{},"Конфігурацію Store з кількома слайсами (",[3769,29257,8430],{},[3769,29259,8419],{},[3836,29261,29262,29263,3869,29265,4631],{},"Типізовані хуки ",[3769,29264,14537],{},[3769,29266,10952],{},[3836,29268,29269],{},"Роботу з діями, перемиканням теми інтерфейсу та оновленням профілю.",[3747,29271,29273],{"id":29272},"структура-файлової-системи-міні-проєкту","Структура файлової системи міні-проєкту",[29275,29276,29277,29284,29291,29298,29305,29312],"code-tree",{},[3762,29278,29282],{"className":29279,"code":29280,"filename":29281,"language":3910,"meta":3767},[3908],"Конфігурація configureStore, експорт RootState та AppDispatch\n","src\u002Fstore\u002Findex.ts",[3769,29283,29280],{"__ignoreMap":3767},[3762,29285,29289],{"className":29286,"code":29287,"filename":29288,"language":3910,"meta":3767},[3908],"Типізовані хуки useAppDispatch, useAppSelector\n","src\u002Fstore\u002Fhooks.ts",[3769,29290,29287],{"__ignoreMap":3767},[3762,29292,29296],{"className":29293,"code":29294,"filename":29295,"language":3910,"meta":3767},[3908],"Слайс теми, мови та статусу сповіщень\n","src\u002Fstore\u002Fslices\u002FsettingsSlice.ts",[3769,29297,29294],{"__ignoreMap":3767},[3762,29299,29303],{"className":29300,"code":29301,"filename":29302,"language":3910,"meta":3767},[3908],"Слайс автентифікації та профілю користувача\n","src\u002Fstore\u002Fslices\u002FuserSlice.ts",[3769,29304,29301],{"__ignoreMap":3767},[3762,29306,29310],{"className":29307,"code":29308,"filename":29309,"language":3910,"meta":3767},[3908],"Екран налаштувань із взаємодією через Redux\n","src\u002Fscreens\u002FSettingsScreen.tsx",[3769,29311,29308],{"__ignoreMap":3767},[3762,29313,29317],{"className":29314,"code":29315,"filename":29316,"language":3910,"meta":3767},[3908],"Точка входу з підключенням Provider\n","App.tsx",[3769,29318,29315],{"__ignoreMap":3767},[3747,29320,29322],{"id":29321},"кроки-реалізації","Кроки реалізації",[29324,29325,29326,29330,29370,29378,29810,30198,30202,30352,30447,30451,32334,32340],"steps",{},[3747,29327,29329],{"id":29328},"крок-1-встановлення-залежностей-1","Крок 1. Встановлення залежностей",[3762,29331,29333],{"className":3764,"code":29332,"language":3766,"meta":3767,"style":3767},"npx create-expo-app@latest settings-demo --template expo-template-blank-typescript\ncd settings-demo\nnpm install @reduxjs\u002Ftoolkit react-redux\n",[3769,29334,29335,29352,29360],{"__ignoreMap":3767},[3772,29336,29337,29340,29343,29346,29349],{"class":3774,"line":3775},[3772,29338,29339],{"class":3778},"npx",[3772,29341,29342],{"class":3781}," create-expo-app@latest",[3772,29344,29345],{"class":3781}," settings-demo",[3772,29347,29348],{"class":3980}," --template",[3772,29350,29351],{"class":3781}," expo-template-blank-typescript\n",[3772,29353,29354,29357],{"class":3774,"line":3938},[3772,29355,29356],{"class":3778},"cd",[3772,29358,29359],{"class":3781}," settings-demo\n",[3772,29361,29362,29364,29366,29368],{"class":3774,"line":3961},[3772,29363,3760],{"class":3778},[3772,29365,3782],{"class":3781},[3772,29367,3785],{"class":3781},[3772,29369,3788],{"class":3781},[3747,29371,29373,29374,3869,29376],{"id":29372},"крок-2-створення-settingsslice-та-userslice","Крок 2. Створення ",[3769,29375,8430],{},[3769,29377,8419],{},[3762,29379,29381],{"className":3925,"code":29380,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FsettingsSlice.ts\nimport { createSlice, PayloadAction } from '@reduxjs\u002Ftoolkit'\n\nexport type ThemeMode = 'light' | 'dark'\nexport type Locale = 'uk' | 'en'\n\ninterface SettingsState {\n    theme: ThemeMode\n    locale: Locale\n    notificationsEnabled: boolean\n}\n\nconst initialState: SettingsState = {\n    theme: 'light',\n    locale: 'uk',\n    notificationsEnabled: true,\n}\n\nexport const settingsSlice = createSlice({\n    name: 'settings',\n    initialState,\n    reducers: {\n        setTheme(state, action: PayloadAction\u003CThemeMode>) {\n            state.theme = action.payload\n        },\n        toggleTheme(state) {\n            state.theme = state.theme === 'light' ? 'dark' : 'light'\n        },\n        setLocale(state, action: PayloadAction\u003CLocale>) {\n            state.locale = action.payload\n        },\n        toggleNotifications(state) {\n            state.notificationsEnabled = !state.notificationsEnabled\n        },\n    },\n})\n\nexport const { setTheme, toggleTheme, setLocale, toggleNotifications } = settingsSlice.actions\nexport default settingsSlice.reducer\n",[3769,29382,29383,29388,29406,29410,29429,29448,29452,29461,29471,29481,29490,29494,29498,29511,29521,29531,29540,29544,29548,29563,29572,29578,29584,29608,29625,29629,29640,29671,29675,29699,29716,29720,29731,29750,29754,29758,29762,29766,29798],{"__ignoreMap":3767},[3772,29384,29385],{"class":3774,"line":3775},[3772,29386,29387],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fslices\u002FsettingsSlice.ts\n",[3772,29389,29390,29392,29394,29396,29398,29400,29402,29404],{"class":3774,"line":3938},[3772,29391,3942],{"class":3941},[3772,29393,3946],{"class":3945},[3772,29395,3846],{"class":3949},[3772,29397,3847],{"class":3945},[3772,29399,6361],{"class":3949},[3772,29401,3952],{"class":3945},[3772,29403,3955],{"class":3941},[3772,29405,3958],{"class":3781},[3772,29407,29408],{"class":3774,"line":3961},[3772,29409,3965],{"emptyLinePlaceholder":3964},[3772,29411,29412,29414,29416,29419,29421,29424,29426],{"class":3774,"line":3968},[3772,29413,3977],{"class":3941},[3772,29415,4039],{"class":3980},[3772,29417,29418],{"class":4042}," ThemeMode",[3772,29420,3988],{"class":3945},[3772,29422,29423],{"class":3781},"'light'",[3772,29425,6462],{"class":3945},[3772,29427,29428],{"class":3781},"'dark'\n",[3772,29430,29431,29433,29435,29438,29440,29443,29445],{"class":3774,"line":3974},[3772,29432,3977],{"class":3941},[3772,29434,4039],{"class":3980},[3772,29436,29437],{"class":4042}," Locale",[3772,29439,3988],{"class":3945},[3772,29441,29442],{"class":3781},"'uk'",[3772,29444,6462],{"class":3945},[3772,29446,29447],{"class":3781},"'en'\n",[3772,29449,29450],{"class":3774,"line":3996},[3772,29451,3965],{"emptyLinePlaceholder":3964},[3772,29453,29454,29456,29459],{"class":3774,"line":4005},[3772,29455,6376],{"class":3980},[3772,29457,29458],{"class":4042}," SettingsState",[3772,29460,4002],{"class":3945},[3772,29462,29463,29466,29468],{"class":3774,"line":4011},[3772,29464,29465],{"class":3949},"    theme",[3772,29467,4800],{"class":3945},[3772,29469,29470],{"class":4042},"ThemeMode\n",[3772,29472,29473,29476,29478],{"class":3774,"line":4017},[3772,29474,29475],{"class":3949},"    locale",[3772,29477,4800],{"class":3945},[3772,29479,29480],{"class":4042},"Locale\n",[3772,29482,29483,29486,29488],{"class":3774,"line":4023},[3772,29484,29485],{"class":3949},"    notificationsEnabled",[3772,29487,4800],{"class":3945},[3772,29489,6449],{"class":4042},[3772,29491,29492],{"class":3774,"line":4028},[3772,29493,4316],{"class":3945},[3772,29495,29496],{"class":3774,"line":4034},[3772,29497,3965],{"emptyLinePlaceholder":3964},[3772,29499,29500,29502,29504,29506,29509],{"class":3774,"line":4068},[3772,29501,5885],{"class":3980},[3772,29503,5888],{"class":3984},[3772,29505,4800],{"class":3945},[3772,29507,29508],{"class":4042},"SettingsState",[3772,29510,5891],{"class":3945},[3772,29512,29513,29516,29519],{"class":3774,"line":4313},[3772,29514,29515],{"class":3949},"    theme:",[3772,29517,29518],{"class":3781}," 'light'",[3772,29520,4806],{"class":3945},[3772,29522,29523,29526,29529],{"class":3774,"line":4470},[3772,29524,29525],{"class":3949},"    locale:",[3772,29527,29528],{"class":3781}," 'uk'",[3772,29530,4806],{"class":3945},[3772,29532,29533,29536,29538],{"class":3774,"line":4879},[3772,29534,29535],{"class":3949},"    notificationsEnabled:",[3772,29537,6116],{"class":3980},[3772,29539,4806],{"class":3945},[3772,29541,29542],{"class":3774,"line":4892},[3772,29543,4316],{"class":3945},[3772,29545,29546],{"class":3774,"line":4903},[3772,29547,3965],{"emptyLinePlaceholder":3964},[3772,29549,29550,29552,29554,29557,29559,29561],{"class":3774,"line":4909},[3772,29551,3977],{"class":3941},[3772,29553,3981],{"class":3980},[3772,29555,29556],{"class":3984}," settingsSlice",[3772,29558,3988],{"class":3945},[3772,29560,3846],{"class":3778},[3772,29562,3993],{"class":3945},[3772,29564,29565,29567,29570],{"class":3774,"line":5521},[3772,29566,6540],{"class":3949},[3772,29568,29569],{"class":3781}," 'settings'",[3772,29571,4806],{"class":3945},[3772,29573,29574,29576],{"class":3774,"line":5527},[3772,29575,6550],{"class":3949},[3772,29577,4806],{"class":3945},[3772,29579,29580,29582],{"class":3774,"line":5533},[3772,29581,6557],{"class":3949},[3772,29583,4002],{"class":3945},[3772,29585,29586,29589,29591,29593,29595,29597,29599,29601,29603,29606],{"class":3774,"line":5539},[3772,29587,29588],{"class":3778},"        setTheme",[3772,29590,5150],{"class":3945},[3772,29592,5153],{"class":3949},[3772,29594,3847],{"class":3945},[3772,29596,5163],{"class":3949},[3772,29598,4800],{"class":3945},[3772,29600,6361],{"class":4042},[3772,29602,4051],{"class":3945},[3772,29604,29605],{"class":4042},"ThemeMode",[3772,29607,6588],{"class":3945},[3772,29609,29610,29612,29614,29617,29619,29621,29623],{"class":3774,"line":5545},[3772,29611,6598],{"class":3949},[3772,29613,4059],{"class":3945},[3772,29615,29616],{"class":3949},"theme",[3772,29618,3988],{"class":3945},[3772,29620,5163],{"class":3949},[3772,29622,4059],{"class":3945},[3772,29624,6750],{"class":3949},[3772,29626,29627],{"class":3774,"line":5550},[3772,29628,6621],{"class":3945},[3772,29630,29631,29634,29636,29638],{"class":3774,"line":6121},[3772,29632,29633],{"class":3778},"        toggleTheme",[3772,29635,5150],{"class":3945},[3772,29637,5153],{"class":3949},[3772,29639,5166],{"class":3945},[3772,29641,29642,29644,29646,29648,29650,29652,29654,29656,29658,29660,29663,29665,29668],{"class":3774,"line":6131},[3772,29643,6598],{"class":3949},[3772,29645,4059],{"class":3945},[3772,29647,29616],{"class":3949},[3772,29649,3988],{"class":3945},[3772,29651,5153],{"class":3949},[3772,29653,4059],{"class":3945},[3772,29655,29616],{"class":3949},[3772,29657,5188],{"class":3945},[3772,29659,29423],{"class":3781},[3772,29661,29662],{"class":3945}," ? ",[3772,29664,4887],{"class":3781},[3772,29666,29667],{"class":3945}," : ",[3772,29669,29670],{"class":3781},"'light'\n",[3772,29672,29673],{"class":3774,"line":6136},[3772,29674,6621],{"class":3945},[3772,29676,29677,29680,29682,29684,29686,29688,29690,29692,29694,29697],{"class":3774,"line":6142},[3772,29678,29679],{"class":3778},"        setLocale",[3772,29681,5150],{"class":3945},[3772,29683,5153],{"class":3949},[3772,29685,3847],{"class":3945},[3772,29687,5163],{"class":3949},[3772,29689,4800],{"class":3945},[3772,29691,6361],{"class":4042},[3772,29693,4051],{"class":3945},[3772,29695,29696],{"class":4042},"Locale",[3772,29698,6588],{"class":3945},[3772,29700,29701,29703,29705,29708,29710,29712,29714],{"class":3774,"line":6150},[3772,29702,6598],{"class":3949},[3772,29704,4059],{"class":3945},[3772,29706,29707],{"class":3949},"locale",[3772,29709,3988],{"class":3945},[3772,29711,5163],{"class":3949},[3772,29713,4059],{"class":3945},[3772,29715,6750],{"class":3949},[3772,29717,29718],{"class":3774,"line":6157},[3772,29719,6621],{"class":3945},[3772,29721,29722,29725,29727,29729],{"class":3774,"line":6162},[3772,29723,29724],{"class":3778},"        toggleNotifications",[3772,29726,5150],{"class":3945},[3772,29728,5153],{"class":3949},[3772,29730,5166],{"class":3945},[3772,29732,29733,29735,29737,29740,29743,29745,29747],{"class":3774,"line":6629},[3772,29734,6598],{"class":3949},[3772,29736,4059],{"class":3945},[3772,29738,29739],{"class":3949},"notificationsEnabled",[3772,29741,29742],{"class":3945}," = !",[3772,29744,5153],{"class":3949},[3772,29746,4059],{"class":3945},[3772,29748,29749],{"class":3949},"notificationsEnabled\n",[3772,29751,29752],{"class":3774,"line":6653},[3772,29753,6621],{"class":3945},[3772,29755,29756],{"class":3774,"line":6698},[3772,29757,4014],{"class":3945},[3772,29759,29760],{"class":3774,"line":6703},[3772,29761,4020],{"class":3945},[3772,29763,29764],{"class":3774,"line":6709},[3772,29765,3965],{"emptyLinePlaceholder":3964},[3772,29767,29768,29770,29772,29774,29776,29778,29781,29783,29785,29787,29790,29792,29794,29796],{"class":3774,"line":6734},[3772,29769,3977],{"class":3941},[3772,29771,3981],{"class":3980},[3772,29773,3946],{"class":3945},[3772,29775,17691],{"class":3984},[3772,29777,3847],{"class":3945},[3772,29779,29780],{"class":3984},"toggleTheme",[3772,29782,3847],{"class":3945},[3772,29784,17696],{"class":3984},[3772,29786,3847],{"class":3945},[3772,29788,29789],{"class":3984},"toggleNotifications",[3772,29791,6801],{"class":3945},[3772,29793,8430],{"class":3949},[3772,29795,4059],{"class":3945},[3772,29797,6809],{"class":3949},[3772,29799,29800,29802,29804,29806,29808],{"class":3774,"line":6753},[3772,29801,3977],{"class":3941},[3772,29803,4196],{"class":3941},[3772,29805,29556],{"class":3949},[3772,29807,4059],{"class":3945},[3772,29809,6834],{"class":3949},[3762,29811,29813],{"className":3925,"code":29812,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FuserSlice.ts\nimport { createSlice, PayloadAction } from '@reduxjs\u002Ftoolkit'\n\ninterface UserProfile {\n    id: string\n    name: string\n    email: string\n    tripsCount: number\n}\n\ninterface UserState {\n    profile: UserProfile | null\n    isAuthenticated: boolean\n}\n\nconst initialState: UserState = {\n    profile: {\n        id: 'u1',\n        name: 'Олексій',\n        email: 'alex@nomad.app',\n        tripsCount: 12,\n    },\n    isAuthenticated: true,\n}\n\nexport const userSlice = createSlice({\n    name: 'user',\n    initialState,\n    reducers: {\n        updateUserName(state, action: PayloadAction\u003Cstring>) {\n            if (state.profile) {\n                state.profile.name = action.payload\n            }\n        },\n        logout(state) {\n            state.profile = null\n            state.isAuthenticated = false\n        },\n    },\n})\n\nexport const { updateUserName, logout } = userSlice.actions\nexport default userSlice.reducer\n",[3769,29814,29815,29819,29837,29841,29850,29858,29867,29876,29885,29889,29893,29902,29916,29925,29929,29933,29946,29953,29963,29973,29983,29993,29997,30006,30010,30014,30028,30036,30042,30048,30071,30085,30105,30109,30113,30123,30135,30147,30151,30155,30159,30163,30186],{"__ignoreMap":3767},[3772,29816,29817],{"class":3774,"line":3775},[3772,29818,14064],{"class":3934},[3772,29820,29821,29823,29825,29827,29829,29831,29833,29835],{"class":3774,"line":3938},[3772,29822,3942],{"class":3941},[3772,29824,3946],{"class":3945},[3772,29826,3846],{"class":3949},[3772,29828,3847],{"class":3945},[3772,29830,6361],{"class":3949},[3772,29832,3952],{"class":3945},[3772,29834,3955],{"class":3941},[3772,29836,3958],{"class":3781},[3772,29838,29839],{"class":3774,"line":3961},[3772,29840,3965],{"emptyLinePlaceholder":3964},[3772,29842,29843,29845,29848],{"class":3774,"line":3968},[3772,29844,6376],{"class":3980},[3772,29846,29847],{"class":4042}," UserProfile",[3772,29849,4002],{"class":3945},[3772,29851,29852,29854,29856],{"class":3774,"line":3974},[3772,29853,6386],{"class":3949},[3772,29855,4800],{"class":3945},[3772,29857,6391],{"class":4042},[3772,29859,29860,29863,29865],{"class":3774,"line":3996},[3772,29861,29862],{"class":3949},"    name",[3772,29864,4800],{"class":3945},[3772,29866,6391],{"class":4042},[3772,29868,29869,29872,29874],{"class":3774,"line":4005},[3772,29870,29871],{"class":3949},"    email",[3772,29873,4800],{"class":3945},[3772,29875,6391],{"class":4042},[3772,29877,29878,29881,29883],{"class":3774,"line":4011},[3772,29879,29880],{"class":3949},"    tripsCount",[3772,29882,4800],{"class":3945},[3772,29884,8507],{"class":4042},[3772,29886,29887],{"class":3774,"line":4017},[3772,29888,4316],{"class":3945},[3772,29890,29891],{"class":3774,"line":4023},[3772,29892,3965],{"emptyLinePlaceholder":3964},[3772,29894,29895,29897,29900],{"class":3774,"line":4028},[3772,29896,6376],{"class":3980},[3772,29898,29899],{"class":4042}," UserState",[3772,29901,4002],{"class":3945},[3772,29903,29904,29907,29909,29912,29914],{"class":3774,"line":4034},[3772,29905,29906],{"class":3949},"    profile",[3772,29908,4800],{"class":3945},[3772,29910,29911],{"class":4042},"UserProfile",[3772,29913,6462],{"class":3945},[3772,29915,4816],{"class":4042},[3772,29917,29918,29921,29923],{"class":3774,"line":4068},[3772,29919,29920],{"class":3949},"    isAuthenticated",[3772,29922,4800],{"class":3945},[3772,29924,6449],{"class":4042},[3772,29926,29927],{"class":3774,"line":4313},[3772,29928,4316],{"class":3945},[3772,29930,29931],{"class":3774,"line":4470},[3772,29932,3965],{"emptyLinePlaceholder":3964},[3772,29934,29935,29937,29939,29941,29944],{"class":3774,"line":4879},[3772,29936,5885],{"class":3980},[3772,29938,5888],{"class":3984},[3772,29940,4800],{"class":3945},[3772,29942,29943],{"class":4042},"UserState",[3772,29945,5891],{"class":3945},[3772,29947,29948,29951],{"class":3774,"line":4892},[3772,29949,29950],{"class":3949},"    profile:",[3772,29952,4002],{"class":3945},[3772,29954,29955,29958,29961],{"class":3774,"line":4903},[3772,29956,29957],{"class":3949},"        id:",[3772,29959,29960],{"class":3781}," 'u1'",[3772,29962,4806],{"class":3945},[3772,29964,29965,29968,29971],{"class":3774,"line":4909},[3772,29966,29967],{"class":3949},"        name:",[3772,29969,29970],{"class":3781}," 'Олексій'",[3772,29972,4806],{"class":3945},[3772,29974,29975,29978,29981],{"class":3774,"line":5521},[3772,29976,29977],{"class":3949},"        email:",[3772,29979,29980],{"class":3781}," 'alex@nomad.app'",[3772,29982,4806],{"class":3945},[3772,29984,29985,29988,29991],{"class":3774,"line":5527},[3772,29986,29987],{"class":3949},"        tripsCount:",[3772,29989,29990],{"class":8916}," 12",[3772,29992,4806],{"class":3945},[3772,29994,29995],{"class":3774,"line":5533},[3772,29996,4014],{"class":3945},[3772,29998,29999,30002,30004],{"class":3774,"line":5539},[3772,30000,30001],{"class":3949},"    isAuthenticated:",[3772,30003,6116],{"class":3980},[3772,30005,4806],{"class":3945},[3772,30007,30008],{"class":3774,"line":5545},[3772,30009,4316],{"class":3945},[3772,30011,30012],{"class":3774,"line":5550},[3772,30013,3965],{"emptyLinePlaceholder":3964},[3772,30015,30016,30018,30020,30022,30024,30026],{"class":3774,"line":6121},[3772,30017,3977],{"class":3941},[3772,30019,3981],{"class":3980},[3772,30021,14073],{"class":3984},[3772,30023,3988],{"class":3945},[3772,30025,3846],{"class":3778},[3772,30027,3993],{"class":3945},[3772,30029,30030,30032,30034],{"class":3774,"line":6131},[3772,30031,6540],{"class":3949},[3772,30033,14086],{"class":3781},[3772,30035,4806],{"class":3945},[3772,30037,30038,30040],{"class":3774,"line":6136},[3772,30039,6550],{"class":3949},[3772,30041,4806],{"class":3945},[3772,30043,30044,30046],{"class":3774,"line":6142},[3772,30045,6557],{"class":3949},[3772,30047,4002],{"class":3945},[3772,30049,30050,30053,30055,30057,30059,30061,30063,30065,30067,30069],{"class":3774,"line":6150},[3772,30051,30052],{"class":3778},"        updateUserName",[3772,30054,5150],{"class":3945},[3772,30056,5153],{"class":3949},[3772,30058,3847],{"class":3945},[3772,30060,5163],{"class":3949},[3772,30062,4800],{"class":3945},[3772,30064,6361],{"class":4042},[3772,30066,4051],{"class":3945},[3772,30068,6459],{"class":4042},[3772,30070,6588],{"class":3945},[3772,30072,30073,30075,30077,30079,30081,30083],{"class":3774,"line":6157},[3772,30074,9043],{"class":3941},[3772,30076,5179],{"class":3945},[3772,30078,5153],{"class":3949},[3772,30080,4059],{"class":3945},[3772,30082,14120],{"class":3949},[3772,30084,5166],{"class":3945},[3772,30086,30087,30089,30091,30093,30095,30097,30099,30101,30103],{"class":3774,"line":6162},[3772,30088,8815],{"class":3949},[3772,30090,4059],{"class":3945},[3772,30092,14120],{"class":3949},[3772,30094,4059],{"class":3945},[3772,30096,4838],{"class":3949},[3772,30098,3988],{"class":3945},[3772,30100,5163],{"class":3949},[3772,30102,4059],{"class":3945},[3772,30104,6750],{"class":3949},[3772,30106,30107],{"class":3774,"line":6629},[3772,30108,6016],{"class":3945},[3772,30110,30111],{"class":3774,"line":6653},[3772,30112,6621],{"class":3945},[3772,30114,30115,30117,30119,30121],{"class":3774,"line":6698},[3772,30116,14105],{"class":3778},[3772,30118,5150],{"class":3945},[3772,30120,5153],{"class":3949},[3772,30122,5166],{"class":3945},[3772,30124,30125,30127,30129,30131,30133],{"class":3774,"line":6703},[3772,30126,6598],{"class":3949},[3772,30128,4059],{"class":3945},[3772,30130,14120],{"class":3949},[3772,30132,3988],{"class":3945},[3772,30134,4816],{"class":3980},[3772,30136,30137,30139,30141,30143,30145],{"class":3774,"line":6709},[3772,30138,6598],{"class":3949},[3772,30140,4059],{"class":3945},[3772,30142,14133],{"class":3949},[3772,30144,3988],{"class":3945},[3772,30146,9324],{"class":3980},[3772,30148,30149],{"class":3774,"line":6734},[3772,30150,6621],{"class":3945},[3772,30152,30153],{"class":3774,"line":6753},[3772,30154,4014],{"class":3945},[3772,30156,30157],{"class":3774,"line":6758},[3772,30158,4020],{"class":3945},[3772,30160,30161],{"class":3774,"line":6763},[3772,30162,3965],{"emptyLinePlaceholder":3964},[3772,30164,30165,30167,30169,30171,30174,30176,30178,30180,30182,30184],{"class":3774,"line":6768},[3772,30166,3977],{"class":3941},[3772,30168,3981],{"class":3980},[3772,30170,3946],{"class":3945},[3772,30172,30173],{"class":3984},"updateUserName",[3772,30175,3847],{"class":3945},[3772,30177,11897],{"class":3984},[3772,30179,6801],{"class":3945},[3772,30181,8419],{"class":3949},[3772,30183,4059],{"class":3945},[3772,30185,6809],{"class":3949},[3772,30187,30188,30190,30192,30194,30196],{"class":3774,"line":6773},[3772,30189,3977],{"class":3941},[3772,30191,4196],{"class":3941},[3772,30193,14073],{"class":3949},[3772,30195,4059],{"class":3945},[3772,30197,6834],{"class":3949},[3747,30199,30201],{"id":30200},"крок-3-налаштування-store-та-типізованих-хуків","Крок 3. Налаштування Store та типізованих хуків",[3762,30203,30205],{"className":3925,"code":30204,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Findex.ts\nimport { configureStore } from '@reduxjs\u002Ftoolkit'\nimport settingsReducer from '.\u002Fslices\u002FsettingsSlice'\nimport userReducer from '.\u002Fslices\u002FuserSlice'\n\nexport const store = configureStore({\n    reducer: {\n        settings: settingsReducer,\n        user: userReducer,\n    },\n    devTools: __DEV__,\n})\n\nexport type RootState = ReturnType\u003Ctypeof store.getState>\nexport type AppDispatch = typeof store.dispatch\n",[3769,30206,30207,30211,30225,30235,30247,30251,30265,30271,30280,30289,30293,30302,30306,30310,30334],{"__ignoreMap":3767},[3772,30208,30209],{"class":3774,"line":3775},[3772,30210,3935],{"class":3934},[3772,30212,30213,30215,30217,30219,30221,30223],{"class":3774,"line":3938},[3772,30214,3942],{"class":3941},[3772,30216,3946],{"class":3945},[3772,30218,3850],{"class":3949},[3772,30220,3952],{"class":3945},[3772,30222,3955],{"class":3941},[3772,30224,3958],{"class":3781},[3772,30226,30227,30229,30231,30233],{"class":3774,"line":3961},[3772,30228,3942],{"class":3941},[3772,30230,17352],{"class":3949},[3772,30232,6211],{"class":3941},[3772,30234,17357],{"class":3781},[3772,30236,30237,30239,30242,30244],{"class":3774,"line":3968},[3772,30238,3942],{"class":3941},[3772,30240,30241],{"class":3949}," userReducer",[3772,30243,6211],{"class":3941},[3772,30245,30246],{"class":3781}," '.\u002Fslices\u002FuserSlice'\n",[3772,30248,30249],{"class":3774,"line":3974},[3772,30250,3965],{"emptyLinePlaceholder":3964},[3772,30252,30253,30255,30257,30259,30261,30263],{"class":3774,"line":3996},[3772,30254,3977],{"class":3941},[3772,30256,3981],{"class":3980},[3772,30258,3985],{"class":3984},[3772,30260,3988],{"class":3945},[3772,30262,3850],{"class":3778},[3772,30264,3993],{"class":3945},[3772,30266,30267,30269],{"class":3774,"line":4005},[3772,30268,3999],{"class":3949},[3772,30270,4002],{"class":3945},[3772,30272,30273,30276,30278],{"class":3774,"line":4011},[3772,30274,30275],{"class":3949},"        settings:",[3772,30277,17352],{"class":3949},[3772,30279,4806],{"class":3945},[3772,30281,30282,30285,30287],{"class":3774,"line":4017},[3772,30283,30284],{"class":3949},"        user:",[3772,30286,30241],{"class":3949},[3772,30288,4806],{"class":3945},[3772,30290,30291],{"class":3774,"line":4023},[3772,30292,4014],{"class":3945},[3772,30294,30295,30297,30300],{"class":3774,"line":4028},[3772,30296,17530],{"class":3949},[3772,30298,30299],{"class":3949}," __DEV__",[3772,30301,4806],{"class":3945},[3772,30303,30304],{"class":3774,"line":4034},[3772,30305,4020],{"class":3945},[3772,30307,30308],{"class":3774,"line":4068},[3772,30309,3965],{"emptyLinePlaceholder":3964},[3772,30311,30312,30314,30316,30318,30320,30322,30324,30326,30328,30330,30332],{"class":3774,"line":4313},[3772,30313,3977],{"class":3941},[3772,30315,4039],{"class":3980},[3772,30317,4043],{"class":4042},[3772,30319,3988],{"class":3945},[3772,30321,4048],{"class":4042},[3772,30323,4051],{"class":3945},[3772,30325,4054],{"class":3980},[3772,30327,3985],{"class":3949},[3772,30329,4059],{"class":3945},[3772,30331,4062],{"class":3949},[3772,30333,4065],{"class":3945},[3772,30335,30336,30338,30340,30342,30344,30346,30348,30350],{"class":3774,"line":4470},[3772,30337,3977],{"class":3941},[3772,30339,4039],{"class":3980},[3772,30341,4075],{"class":4042},[3772,30343,3988],{"class":3945},[3772,30345,4054],{"class":3980},[3772,30347,3985],{"class":3949},[3772,30349,4059],{"class":3945},[3772,30351,4086],{"class":3949},[3762,30353,30355],{"className":3925,"code":30354,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fhooks.ts\nimport { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux'\nimport type { RootState, AppDispatch } from '.\u002Findex'\n\nexport const useAppDispatch = () => useDispatch\u003CAppDispatch>()\nexport const useAppSelector: TypedUseSelectorHook\u003CRootState> = useSelector\n",[3769,30356,30357,30361,30383,30403,30407,30427],{"__ignoreMap":3767},[3772,30358,30359],{"class":3774,"line":3775},[3772,30360,18926],{"class":3934},[3772,30362,30363,30365,30367,30369,30371,30373,30375,30377,30379,30381],{"class":3774,"line":3938},[3772,30364,3942],{"class":3941},[3772,30366,3946],{"class":3945},[3772,30368,3872],{"class":3949},[3772,30370,3847],{"class":3945},[3772,30372,3868],{"class":3949},[3772,30374,3847],{"class":3945},[3772,30376,18943],{"class":3949},[3772,30378,3952],{"class":3945},[3772,30380,3955],{"class":3941},[3772,30382,4153],{"class":3781},[3772,30384,30385,30387,30389,30391,30393,30395,30397,30399,30401],{"class":3774,"line":3961},[3772,30386,3942],{"class":3941},[3772,30388,4039],{"class":3941},[3772,30390,3946],{"class":3945},[3772,30392,14962],{"class":3949},[3772,30394,3847],{"class":3945},[3772,30396,17675],{"class":3949},[3772,30398,3952],{"class":3945},[3772,30400,3955],{"class":3941},[3772,30402,17682],{"class":3781},[3772,30404,30405],{"class":3774,"line":3968},[3772,30406,3965],{"emptyLinePlaceholder":3964},[3772,30408,30409,30411,30413,30415,30417,30419,30421,30423,30425],{"class":3774,"line":3974},[3772,30410,3977],{"class":3941},[3772,30412,3981],{"class":3980},[3772,30414,18987],{"class":3778},[3772,30416,14701],{"class":3945},[3772,30418,5768],{"class":3980},[3772,30420,18994],{"class":3778},[3772,30422,4051],{"class":3945},[3772,30424,17675],{"class":4042},[3772,30426,17774],{"class":3945},[3772,30428,30429,30431,30433,30435,30437,30439,30441,30443,30445],{"class":3774,"line":3996},[3772,30430,3977],{"class":3941},[3772,30432,3981],{"class":3980},[3772,30434,19018],{"class":3984},[3772,30436,4800],{"class":3945},[3772,30438,18943],{"class":4042},[3772,30440,4051],{"class":3945},[3772,30442,14962],{"class":4042},[3772,30444,19029],{"class":3945},[3772,30446,19032],{"class":3949},[3747,30448,30450],{"id":30449},"крок-4-створення-екрана-налаштувань","Крок 4. Створення екрана налаштувань",[3762,30452,30454],{"className":4129,"code":30453,"language":4131,"meta":3767,"style":3767},"\u002F\u002F src\u002Fscreens\u002FSettingsScreen.tsx\nimport React from 'react'\nimport { View, Text, Pressable, StyleSheet } from 'react-native'\nimport { useAppSelector, useAppDispatch } from '..\u002Fstore\u002Fhooks'\nimport { setTheme, setLocale, toggleNotifications, type ThemeMode, type Locale } from '..\u002Fstore\u002Fslices\u002FsettingsSlice'\n\nexport default function SettingsScreen() {\n    const dispatch = useAppDispatch()\n    const { theme, locale, notificationsEnabled } = useAppSelector((state) => state.settings)\n    const user = useAppSelector((state) => state.user.profile)\n\n    const isDark = theme === 'dark'\n    const bgColor = isDark ? '#0f172a' : '#ffffff'\n    const textColor = isDark ? '#f8fafc' : '#0f172a'\n    const cardBg = isDark ? '#1e293b' : '#f1f5f9'\n\n    const themes: ThemeMode[] = ['light', 'dark']\n    const locales: { id: Locale; label: string }[] = [\n        { id: 'uk', label: 'Українська' },\n        { id: 'en', label: 'English' },\n    ]\n\n    return (\n        \u003CView style={[styles.container, { backgroundColor: bgColor }]}>\n            \u003CText style={[styles.title, { color: textColor }]}>Налаштування\u003C\u002FText>\n\n            {user && (\n                \u003CView style={[styles.userCard, { backgroundColor: cardBg }]}>\n                    \u003CText style={[styles.userName, { color: textColor }]}>{user.name}\u003C\u002FText>\n                    \u003CText style={styles.userEmail}>{user.email}\u003C\u002FText>\n                    \u003CText style={styles.userTrips}>Всього поїздок: {user.tripsCount}\u003C\u002FText>\n                \u003C\u002FView>\n            )}\n\n            \u003CView style={styles.section}>\n                \u003CText style={[styles.sectionTitle, { color: textColor }]}>Тема інтерфейсу\u003C\u002FText>\n                \u003CView style={styles.row}>\n                    {themes.map((t) => (\n                        \u003CPressable\n                            key={t}\n                            onPress={() => dispatch(setTheme(t))}\n                            style={[styles.chip, { backgroundColor: theme === t ? '#2563eb' : cardBg }]}\n                        >\n                            \u003CText style={{ color: theme === t ? '#ffffff' : textColor, fontWeight: '600' }}>\n                                {t === 'light' ? '☀️ Світла' : '🌙 Темна'}\n                            \u003C\u002FText>\n                        \u003C\u002FPressable>\n                    ))}\n                \u003C\u002FView>\n            \u003C\u002FView>\n\n            \u003CView style={styles.section}>\n                \u003CText style={[styles.sectionTitle, { color: textColor }]}>Мова застосунку\u003C\u002FText>\n                \u003CView style={styles.row}>\n                    {locales.map((l) => (\n                        \u003CPressable\n                            key={l.id}\n                            onPress={() => dispatch(setLocale(l.id))}\n                            style={[styles.chip, { backgroundColor: locale === l.id ? '#2563eb' : cardBg }]}\n                        >\n                            \u003CText style={{ color: locale === l.id ? '#ffffff' : textColor, fontWeight: '600' }}>\n                                {l.label}\n                            \u003C\u002FText>\n                        \u003C\u002FPressable>\n                    ))}\n                \u003C\u002FView>\n            \u003C\u002FView>\n\n            \u003CView style={styles.section}>\n                \u003CPressable\n                    onPress={() => dispatch(toggleNotifications())}\n                    style={[styles.toggleButton, { backgroundColor: cardBg }]}\n                >\n                    \u003CText style={[styles.toggleText, { color: textColor }]}>Сповіщення\u003C\u002FText>\n                    \u003CText style={{ color: notificationsEnabled ? '#059669' : '#dc2626', fontWeight: '700' }}>\n                        {notificationsEnabled ? 'УВІМКНЕНО' : 'ВИМКНЕНО'}\n                    \u003C\u002FText>\n                \u003C\u002FPressable>\n            \u003C\u002FView>\n        \u003C\u002FView>\n    )\n}\n\nconst styles = StyleSheet.create({\n    container: { flex: 1, padding: 20 },\n    title: { fontSize: 28, fontWeight: '800', marginBottom: 20 },\n    userCard: { padding: 16, borderRadius: 12, marginBottom: 24 },\n    userName: { fontSize: 18, fontWeight: '700' },\n    userEmail: { fontSize: 13, color: '#64748b', marginTop: 2 },\n    userTrips: { fontSize: 13, color: '#2563eb', fontWeight: '600', marginTop: 8 },\n    section: { marginBottom: 20 },\n    sectionTitle: { fontSize: 15, fontWeight: '600', marginBottom: 10 },\n    row: { flexDirection: 'row', gap: 10 },\n    chip: { paddingVertical: 10, paddingHorizontal: 16, borderRadius: 8 },\n    toggleButton: {\n        flexDirection: 'row',\n        justifyContent: 'space-between',\n        alignItems: 'center',\n        padding: 16,\n        borderRadius: 12,\n    },\n    toggleText: { fontSize: 15, fontWeight: '600' },\n})\n",[3769,30455,30456,30461,30471,30498,30517,30552,30556,30569,30581,30617,30648,30652,30667,30689,30710,30731,30735,30758,30785,30803,30821,30826,30830,30836,30873,30915,30919,30931,30964,31014,31053,31096,31105,31112,31116,31139,31181,31204,31226,31234,31247,31275,31318,31323,31369,31392,31401,31410,31417,31425,31433,31437,31459,31500,31522,31544,31550,31566,31596,31640,31644,31690,31702,31710,31718,31724,31732,31740,31744,31766,31772,31796,31824,31829,31871,31913,31932,31941,31949,31957,31965,31969,31973,31977,31995,32016,32044,32072,32092,32121,32153,32166,32193,32216,32244,32252,32262,32273,32284,32294,32304,32309,32329],{"__ignoreMap":3767},[3772,30457,30458],{"class":3774,"line":3775},[3772,30459,30460],{"class":3934},"\u002F\u002F src\u002Fscreens\u002FSettingsScreen.tsx\n",[3772,30462,30463,30465,30467,30469],{"class":3774,"line":3938},[3772,30464,3942],{"class":3941},[3772,30466,14502],{"class":3949},[3772,30468,6211],{"class":3941},[3772,30470,14507],{"class":3781},[3772,30472,30473,30475,30477,30479,30481,30483,30485,30487,30489,30492,30494,30496],{"class":3774,"line":3961},[3772,30474,3942],{"class":3941},[3772,30476,3946],{"class":3945},[3772,30478,19205],{"class":3949},[3772,30480,3847],{"class":3945},[3772,30482,14521],{"class":3949},[3772,30484,3847],{"class":3945},[3772,30486,14516],{"class":3949},[3772,30488,3847],{"class":3945},[3772,30490,30491],{"class":3949},"StyleSheet",[3772,30493,3952],{"class":3945},[3772,30495,3955],{"class":3941},[3772,30497,14528],{"class":3781},[3772,30499,30500,30502,30504,30506,30508,30510,30512,30514],{"class":3774,"line":3968},[3772,30501,3942],{"class":3941},[3772,30503,3946],{"class":3945},[3772,30505,10952],{"class":3949},[3772,30507,3847],{"class":3945},[3772,30509,14537],{"class":3949},[3772,30511,3952],{"class":3945},[3772,30513,3955],{"class":3941},[3772,30515,30516],{"class":3781}," '..\u002Fstore\u002Fhooks'\n",[3772,30518,30519,30521,30523,30525,30527,30529,30531,30533,30535,30537,30539,30541,30543,30545,30547,30549],{"class":3774,"line":3974},[3772,30520,3942],{"class":3941},[3772,30522,3946],{"class":3945},[3772,30524,17691],{"class":3949},[3772,30526,3847],{"class":3945},[3772,30528,17696],{"class":3949},[3772,30530,3847],{"class":3945},[3772,30532,29789],{"class":3949},[3772,30534,3847],{"class":3945},[3772,30536,5048],{"class":3941},[3772,30538,29418],{"class":3949},[3772,30540,3847],{"class":3945},[3772,30542,5048],{"class":3941},[3772,30544,29437],{"class":3949},[3772,30546,3952],{"class":3945},[3772,30548,3955],{"class":3941},[3772,30550,30551],{"class":3781}," '..\u002Fstore\u002Fslices\u002FsettingsSlice'\n",[3772,30553,30554],{"class":3774,"line":3996},[3772,30555,3965],{"emptyLinePlaceholder":3964},[3772,30557,30558,30560,30562,30564,30567],{"class":3774,"line":4005},[3772,30559,3977],{"class":3941},[3772,30561,4196],{"class":3941},[3772,30563,4199],{"class":3980},[3772,30565,30566],{"class":3778}," SettingsScreen",[3772,30568,4205],{"class":3945},[3772,30570,30571,30573,30575,30577,30579],{"class":3774,"line":4011},[3772,30572,10944],{"class":3980},[3772,30574,14600],{"class":3984},[3772,30576,3988],{"class":3945},[3772,30578,14537],{"class":3778},[3772,30580,13941],{"class":3945},[3772,30582,30583,30585,30587,30589,30591,30593,30595,30597,30599,30601,30603,30605,30607,30609,30611,30613,30615],{"class":3774,"line":4017},[3772,30584,10944],{"class":3980},[3772,30586,3946],{"class":3945},[3772,30588,29616],{"class":3984},[3772,30590,3847],{"class":3945},[3772,30592,29707],{"class":3984},[3772,30594,3847],{"class":3945},[3772,30596,29739],{"class":3984},[3772,30598,6801],{"class":3945},[3772,30600,10952],{"class":3778},[3772,30602,6056],{"class":3945},[3772,30604,5153],{"class":3949},[3772,30606,5765],{"class":3945},[3772,30608,5768],{"class":3980},[3772,30610,5353],{"class":3949},[3772,30612,4059],{"class":3945},[3772,30614,17871],{"class":3949},[3772,30616,5345],{"class":3945},[3772,30618,30619,30621,30624,30626,30628,30630,30632,30634,30636,30638,30640,30642,30644,30646],{"class":3774,"line":4023},[3772,30620,10944],{"class":3980},[3772,30622,30623],{"class":3984}," user",[3772,30625,3988],{"class":3945},[3772,30627,10952],{"class":3778},[3772,30629,6056],{"class":3945},[3772,30631,5153],{"class":3949},[3772,30633,5765],{"class":3945},[3772,30635,5768],{"class":3980},[3772,30637,5353],{"class":3949},[3772,30639,4059],{"class":3945},[3772,30641,19140],{"class":3949},[3772,30643,4059],{"class":3945},[3772,30645,14120],{"class":3949},[3772,30647,5345],{"class":3945},[3772,30649,30650],{"class":3774,"line":4028},[3772,30651,3965],{"emptyLinePlaceholder":3964},[3772,30653,30654,30656,30659,30661,30663,30665],{"class":3774,"line":4034},[3772,30655,10944],{"class":3980},[3772,30657,30658],{"class":3984}," isDark",[3772,30660,3988],{"class":3945},[3772,30662,29616],{"class":3949},[3772,30664,5188],{"class":3945},[3772,30666,29428],{"class":3781},[3772,30668,30669,30671,30674,30676,30679,30681,30684,30686],{"class":3774,"line":4068},[3772,30670,10944],{"class":3980},[3772,30672,30673],{"class":3984}," bgColor",[3772,30675,3988],{"class":3945},[3772,30677,30678],{"class":3949},"isDark",[3772,30680,29662],{"class":3945},[3772,30682,30683],{"class":3781},"'#0f172a'",[3772,30685,29667],{"class":3945},[3772,30687,30688],{"class":3781},"'#ffffff'\n",[3772,30690,30691,30693,30696,30698,30700,30702,30705,30707],{"class":3774,"line":4313},[3772,30692,10944],{"class":3980},[3772,30694,30695],{"class":3984}," textColor",[3772,30697,3988],{"class":3945},[3772,30699,30678],{"class":3949},[3772,30701,29662],{"class":3945},[3772,30703,30704],{"class":3781},"'#f8fafc'",[3772,30706,29667],{"class":3945},[3772,30708,30709],{"class":3781},"'#0f172a'\n",[3772,30711,30712,30714,30717,30719,30721,30723,30726,30728],{"class":3774,"line":4470},[3772,30713,10944],{"class":3980},[3772,30715,30716],{"class":3984}," cardBg",[3772,30718,3988],{"class":3945},[3772,30720,30678],{"class":3949},[3772,30722,29662],{"class":3945},[3772,30724,30725],{"class":3781},"'#1e293b'",[3772,30727,29667],{"class":3945},[3772,30729,30730],{"class":3781},"'#f1f5f9'\n",[3772,30732,30733],{"class":3774,"line":4879},[3772,30734,3965],{"emptyLinePlaceholder":3964},[3772,30736,30737,30739,30742,30744,30746,30749,30751,30753,30755],{"class":3774,"line":4892},[3772,30738,10944],{"class":3980},[3772,30740,30741],{"class":3984}," themes",[3772,30743,4800],{"class":3945},[3772,30745,29605],{"class":4042},[3772,30747,30748],{"class":3945},"[] = [",[3772,30750,29423],{"class":3781},[3772,30752,3847],{"class":3945},[3772,30754,4887],{"class":3781},[3772,30756,30757],{"class":3945},"]\n",[3772,30759,30760,30762,30765,30767,30769,30771,30773,30775,30778,30780,30782],{"class":3774,"line":4903},[3772,30761,10944],{"class":3980},[3772,30763,30764],{"class":3984}," locales",[3772,30766,4835],{"class":3945},[3772,30768,5812],{"class":3949},[3772,30770,4800],{"class":3945},[3772,30772,29696],{"class":4042},[3772,30774,7818],{"class":3945},[3772,30776,30777],{"class":3949},"label",[3772,30779,4800],{"class":3945},[3772,30781,6459],{"class":4042},[3772,30783,30784],{"class":3945}," }[] = [\n",[3772,30786,30787,30789,30791,30793,30795,30798,30801],{"class":3774,"line":4909},[3772,30788,21162],{"class":3945},[3772,30790,4739],{"class":3949},[3772,30792,29528],{"class":3781},[3772,30794,3847],{"class":3945},[3772,30796,30797],{"class":3949},"label:",[3772,30799,30800],{"class":3781}," 'Українська'",[3772,30802,4761],{"class":3945},[3772,30804,30805,30807,30809,30812,30814,30816,30819],{"class":3774,"line":5521},[3772,30806,21162],{"class":3945},[3772,30808,4739],{"class":3949},[3772,30810,30811],{"class":3781}," 'en'",[3772,30813,3847],{"class":3945},[3772,30815,30797],{"class":3949},[3772,30817,30818],{"class":3781}," 'English'",[3772,30820,4761],{"class":3945},[3772,30822,30823],{"class":3774,"line":5527},[3772,30824,30825],{"class":3945},"    ]\n",[3772,30827,30828],{"class":3774,"line":5533},[3772,30829,3965],{"emptyLinePlaceholder":3964},[3772,30831,30832,30834],{"class":3774,"line":5539},[3772,30833,4210],{"class":3941},[3772,30835,4213],{"class":3945},[3772,30837,30838,30840,30842,30845,30847,30849,30851,30854,30856,30859,30861,30864,30866,30869,30871],{"class":3774,"line":5545},[3772,30839,4219],{"class":4218},[3772,30841,19205],{"class":4042},[3772,30843,30844],{"class":4224}," style",[3772,30846,4227],{"class":3945},[3772,30848,4230],{"class":3980},[3772,30850,10793],{"class":4272},[3772,30852,30853],{"class":3949},"styles",[3772,30855,4059],{"class":4272},[3772,30857,30858],{"class":3949},"container",[3772,30860,20886],{"class":4272},[3772,30862,30863],{"class":3949},"backgroundColor:",[3772,30865,30673],{"class":3949},[3772,30867,30868],{"class":4272}," }]",[3772,30870,4235],{"class":3980},[3772,30872,4065],{"class":4218},[3772,30874,30875,30877,30879,30881,30883,30885,30887,30889,30891,30893,30895,30898,30900,30902,30904,30906,30909,30911,30913],{"class":3774,"line":5550},[3772,30876,4242],{"class":4218},[3772,30878,14521],{"class":4042},[3772,30880,30844],{"class":4224},[3772,30882,4227],{"class":3945},[3772,30884,4230],{"class":3980},[3772,30886,10793],{"class":4272},[3772,30888,30853],{"class":3949},[3772,30890,4059],{"class":4272},[3772,30892,7131],{"class":3949},[3772,30894,20886],{"class":4272},[3772,30896,30897],{"class":3949},"color:",[3772,30899,30695],{"class":3949},[3772,30901,30868],{"class":4272},[3772,30903,4235],{"class":3980},[3772,30905,14780],{"class":4218},[3772,30907,30908],{"class":3945},"Налаштування",[3772,30910,14802],{"class":4218},[3772,30912,14521],{"class":4042},[3772,30914,4065],{"class":4218},[3772,30916,30917],{"class":3774,"line":6121},[3772,30918,3965],{"emptyLinePlaceholder":3964},[3772,30920,30921,30924,30926,30929],{"class":3774,"line":6131},[3772,30922,30923],{"class":3980},"            {",[3772,30925,19140],{"class":3949},[3772,30927,30928],{"class":3945}," &&",[3772,30930,4213],{"class":4272},[3772,30932,30933,30935,30937,30939,30941,30943,30945,30947,30949,30952,30954,30956,30958,30960,30962],{"class":3774,"line":6136},[3772,30934,4251],{"class":4218},[3772,30936,19205],{"class":4042},[3772,30938,30844],{"class":4224},[3772,30940,4227],{"class":3945},[3772,30942,4230],{"class":3980},[3772,30944,10793],{"class":4272},[3772,30946,30853],{"class":3949},[3772,30948,4059],{"class":4272},[3772,30950,30951],{"class":3949},"userCard",[3772,30953,20886],{"class":4272},[3772,30955,30863],{"class":3949},[3772,30957,30716],{"class":3949},[3772,30959,30868],{"class":4272},[3772,30961,4235],{"class":3980},[3772,30963,4065],{"class":4218},[3772,30965,30966,30969,30971,30973,30975,30977,30979,30981,30983,30986,30988,30990,30992,30994,30996,30998,31000,31002,31004,31006,31008,31010,31012],{"class":3774,"line":6142},[3772,30967,30968],{"class":4218},"                    \u003C",[3772,30970,14521],{"class":4042},[3772,30972,30844],{"class":4224},[3772,30974,4227],{"class":3945},[3772,30976,4230],{"class":3980},[3772,30978,10793],{"class":4272},[3772,30980,30853],{"class":3949},[3772,30982,4059],{"class":4272},[3772,30984,30985],{"class":3949},"userName",[3772,30987,20886],{"class":4272},[3772,30989,30897],{"class":3949},[3772,30991,30695],{"class":3949},[3772,30993,30868],{"class":4272},[3772,30995,4235],{"class":3980},[3772,30997,14780],{"class":4218},[3772,30999,4230],{"class":3980},[3772,31001,19140],{"class":3949},[3772,31003,4059],{"class":4272},[3772,31005,4838],{"class":3949},[3772,31007,4235],{"class":3980},[3772,31009,14802],{"class":4218},[3772,31011,14521],{"class":4042},[3772,31013,4065],{"class":4218},[3772,31015,31016,31018,31020,31022,31024,31026,31028,31030,31033,31035,31037,31039,31041,31043,31045,31047,31049,31051],{"class":3774,"line":6150},[3772,31017,30968],{"class":4218},[3772,31019,14521],{"class":4042},[3772,31021,30844],{"class":4224},[3772,31023,4227],{"class":3945},[3772,31025,4230],{"class":3980},[3772,31027,30853],{"class":3949},[3772,31029,4059],{"class":4272},[3772,31031,31032],{"class":3949},"userEmail",[3772,31034,4235],{"class":3980},[3772,31036,14780],{"class":4218},[3772,31038,4230],{"class":3980},[3772,31040,19140],{"class":3949},[3772,31042,4059],{"class":4272},[3772,31044,4848],{"class":3949},[3772,31046,4235],{"class":3980},[3772,31048,14802],{"class":4218},[3772,31050,14521],{"class":4042},[3772,31052,4065],{"class":4218},[3772,31054,31055,31057,31059,31061,31063,31065,31067,31069,31072,31074,31076,31079,31081,31083,31085,31088,31090,31092,31094],{"class":3774,"line":6157},[3772,31056,30968],{"class":4218},[3772,31058,14521],{"class":4042},[3772,31060,30844],{"class":4224},[3772,31062,4227],{"class":3945},[3772,31064,4230],{"class":3980},[3772,31066,30853],{"class":3949},[3772,31068,4059],{"class":4272},[3772,31070,31071],{"class":3949},"userTrips",[3772,31073,4235],{"class":3980},[3772,31075,14780],{"class":4218},[3772,31077,31078],{"class":4272},"Всього поїздок: ",[3772,31080,4230],{"class":3980},[3772,31082,19140],{"class":3949},[3772,31084,4059],{"class":4272},[3772,31086,31087],{"class":3949},"tripsCount",[3772,31089,4235],{"class":3980},[3772,31091,14802],{"class":4218},[3772,31093,14521],{"class":4042},[3772,31095,4065],{"class":4218},[3772,31097,31098,31101,31103],{"class":3774,"line":6162},[3772,31099,31100],{"class":4218},"                \u003C\u002F",[3772,31102,19205],{"class":4042},[3772,31104,4065],{"class":4218},[3772,31106,31107,31110],{"class":3774,"line":6629},[3772,31108,31109],{"class":4272},"            )",[3772,31111,4316],{"class":3980},[3772,31113,31114],{"class":3774,"line":6653},[3772,31115,3965],{"emptyLinePlaceholder":3964},[3772,31117,31118,31120,31122,31124,31126,31128,31130,31132,31135,31137],{"class":3774,"line":6698},[3772,31119,4242],{"class":4218},[3772,31121,19205],{"class":4042},[3772,31123,30844],{"class":4224},[3772,31125,4227],{"class":3945},[3772,31127,4230],{"class":3980},[3772,31129,30853],{"class":3949},[3772,31131,4059],{"class":4272},[3772,31133,31134],{"class":3949},"section",[3772,31136,4235],{"class":3980},[3772,31138,4065],{"class":4218},[3772,31140,31141,31143,31145,31147,31149,31151,31153,31155,31157,31160,31162,31164,31166,31168,31170,31172,31175,31177,31179],{"class":3774,"line":6703},[3772,31142,4251],{"class":4218},[3772,31144,14521],{"class":4042},[3772,31146,30844],{"class":4224},[3772,31148,4227],{"class":3945},[3772,31150,4230],{"class":3980},[3772,31152,10793],{"class":4272},[3772,31154,30853],{"class":3949},[3772,31156,4059],{"class":4272},[3772,31158,31159],{"class":3949},"sectionTitle",[3772,31161,20886],{"class":4272},[3772,31163,30897],{"class":3949},[3772,31165,30695],{"class":3949},[3772,31167,30868],{"class":4272},[3772,31169,4235],{"class":3980},[3772,31171,14780],{"class":4218},[3772,31173,31174],{"class":3945},"Тема інтерфейсу",[3772,31176,14802],{"class":4218},[3772,31178,14521],{"class":4042},[3772,31180,4065],{"class":4218},[3772,31182,31183,31185,31187,31189,31191,31193,31195,31197,31200,31202],{"class":3774,"line":6709},[3772,31184,4251],{"class":4218},[3772,31186,19205],{"class":4042},[3772,31188,30844],{"class":4224},[3772,31190,4227],{"class":3945},[3772,31192,4230],{"class":3980},[3772,31194,30853],{"class":3949},[3772,31196,4059],{"class":4272},[3772,31198,31199],{"class":3949},"row",[3772,31201,4235],{"class":3980},[3772,31203,4065],{"class":4218},[3772,31205,31206,31209,31212,31214,31216,31218,31220,31222,31224],{"class":3774,"line":6734},[3772,31207,31208],{"class":3980},"                    {",[3772,31210,31211],{"class":3949},"themes",[3772,31213,4059],{"class":4272},[3772,31215,7562],{"class":3778},[3772,31217,6056],{"class":4272},[3772,31219,6059],{"class":3949},[3772,31221,5765],{"class":4272},[3772,31223,5768],{"class":3980},[3772,31225,4213],{"class":4272},[3772,31227,31228,31231],{"class":3774,"line":6753},[3772,31229,31230],{"class":4218},"                        \u003C",[3772,31232,31233],{"class":4042},"Pressable\n",[3772,31235,31236,31239,31241,31243,31245],{"class":3774,"line":6758},[3772,31237,31238],{"class":4224},"                            key",[3772,31240,4227],{"class":3945},[3772,31242,4230],{"class":3980},[3772,31244,6059],{"class":3949},[3772,31246,4316],{"class":3980},[3772,31248,31249,31252,31254,31256,31258,31260,31262,31264,31266,31268,31270,31273],{"class":3774,"line":6763},[3772,31250,31251],{"class":4224},"                            onPress",[3772,31253,4227],{"class":3945},[3772,31255,4230],{"class":3980},[3772,31257,20154],{"class":4272},[3772,31259,5768],{"class":3980},[3772,31261,14600],{"class":3778},[3772,31263,5150],{"class":4272},[3772,31265,17691],{"class":3778},[3772,31267,5150],{"class":4272},[3772,31269,6059],{"class":3949},[3772,31271,31272],{"class":4272},"))",[3772,31274,4316],{"class":3980},[3772,31276,31277,31280,31282,31284,31286,31288,31290,31293,31295,31297,31300,31303,31305,31307,31310,31312,31314,31316],{"class":3774,"line":6768},[3772,31278,31279],{"class":4224},"                            style",[3772,31281,4227],{"class":3945},[3772,31283,4230],{"class":3980},[3772,31285,10793],{"class":4272},[3772,31287,30853],{"class":3949},[3772,31289,4059],{"class":4272},[3772,31291,31292],{"class":3949},"chip",[3772,31294,20886],{"class":4272},[3772,31296,30863],{"class":3949},[3772,31298,31299],{"class":3949}," theme",[3772,31301,31302],{"class":3945}," ===",[3772,31304,6066],{"class":3949},[3772,31306,14788],{"class":3945},[3772,31308,31309],{"class":3781}," '#2563eb'",[3772,31311,14794],{"class":3945},[3772,31313,30716],{"class":3949},[3772,31315,30868],{"class":4272},[3772,31317,4316],{"class":3980},[3772,31319,31320],{"class":3774,"line":6773},[3772,31321,31322],{"class":4218},"                        >\n",[3772,31324,31325,31328,31330,31332,31334,31336,31338,31340,31342,31344,31346,31348,31351,31353,31355,31357,31360,31363,31365,31367],{"class":3774,"line":6779},[3772,31326,31327],{"class":4218},"                            \u003C",[3772,31329,14521],{"class":4042},[3772,31331,30844],{"class":4224},[3772,31333,4227],{"class":3945},[3772,31335,4230],{"class":3980},[3772,31337,4273],{"class":4272},[3772,31339,30897],{"class":3949},[3772,31341,31299],{"class":3949},[3772,31343,31302],{"class":3945},[3772,31345,6066],{"class":3949},[3772,31347,14788],{"class":3945},[3772,31349,31350],{"class":3781}," '#ffffff'",[3772,31352,14794],{"class":3945},[3772,31354,30695],{"class":3949},[3772,31356,3847],{"class":4272},[3772,31358,31359],{"class":3949},"fontWeight:",[3772,31361,31362],{"class":3781}," '600'",[3772,31364,4282],{"class":4272},[3772,31366,4235],{"class":3980},[3772,31368,4065],{"class":4218},[3772,31370,31371,31374,31376,31378,31380,31382,31385,31387,31390],{"class":3774,"line":6812},[3772,31372,31373],{"class":3980},"                                {",[3772,31375,6059],{"class":3949},[3772,31377,31302],{"class":3945},[3772,31379,29518],{"class":3781},[3772,31381,14788],{"class":3945},[3772,31383,31384],{"class":3781}," '☀️ Світла'",[3772,31386,14794],{"class":3945},[3772,31388,31389],{"class":3781}," '🌙 Темна'",[3772,31391,4316],{"class":3980},[3772,31393,31394,31397,31399],{"class":3774,"line":6817},[3772,31395,31396],{"class":4218},"                            \u003C\u002F",[3772,31398,14521],{"class":4042},[3772,31400,4065],{"class":4218},[3772,31402,31403,31406,31408],{"class":3774,"line":6823},[3772,31404,31405],{"class":4218},"                        \u003C\u002F",[3772,31407,14516],{"class":4042},[3772,31409,4065],{"class":4218},[3772,31411,31412,31415],{"class":3774,"line":8841},[3772,31413,31414],{"class":4272},"                    ))",[3772,31416,4316],{"class":3980},[3772,31418,31419,31421,31423],{"class":3774,"line":8865},[3772,31420,31100],{"class":4218},[3772,31422,19205],{"class":4042},[3772,31424,4065],{"class":4218},[3772,31426,31427,31429,31431],{"class":3774,"line":8873},[3772,31428,4292],{"class":4218},[3772,31430,19205],{"class":4042},[3772,31432,4065],{"class":4218},[3772,31434,31435],{"class":3774,"line":8881},[3772,31436,3965],{"emptyLinePlaceholder":3964},[3772,31438,31439,31441,31443,31445,31447,31449,31451,31453,31455,31457],{"class":3774,"line":8894},[3772,31440,4242],{"class":4218},[3772,31442,19205],{"class":4042},[3772,31444,30844],{"class":4224},[3772,31446,4227],{"class":3945},[3772,31448,4230],{"class":3980},[3772,31450,30853],{"class":3949},[3772,31452,4059],{"class":4272},[3772,31454,31134],{"class":3949},[3772,31456,4235],{"class":3980},[3772,31458,4065],{"class":4218},[3772,31460,31461,31463,31465,31467,31469,31471,31473,31475,31477,31479,31481,31483,31485,31487,31489,31491,31494,31496,31498],{"class":3774,"line":8902},[3772,31462,4251],{"class":4218},[3772,31464,14521],{"class":4042},[3772,31466,30844],{"class":4224},[3772,31468,4227],{"class":3945},[3772,31470,4230],{"class":3980},[3772,31472,10793],{"class":4272},[3772,31474,30853],{"class":3949},[3772,31476,4059],{"class":4272},[3772,31478,31159],{"class":3949},[3772,31480,20886],{"class":4272},[3772,31482,30897],{"class":3949},[3772,31484,30695],{"class":3949},[3772,31486,30868],{"class":4272},[3772,31488,4235],{"class":3980},[3772,31490,14780],{"class":4218},[3772,31492,31493],{"class":3945},"Мова застосунку",[3772,31495,14802],{"class":4218},[3772,31497,14521],{"class":4042},[3772,31499,4065],{"class":4218},[3772,31501,31502,31504,31506,31508,31510,31512,31514,31516,31518,31520],{"class":3774,"line":8910},[3772,31503,4251],{"class":4218},[3772,31505,19205],{"class":4042},[3772,31507,30844],{"class":4224},[3772,31509,4227],{"class":3945},[3772,31511,4230],{"class":3980},[3772,31513,30853],{"class":3949},[3772,31515,4059],{"class":4272},[3772,31517,31199],{"class":3949},[3772,31519,4235],{"class":3980},[3772,31521,4065],{"class":4218},[3772,31523,31524,31526,31529,31531,31533,31535,31538,31540,31542],{"class":3774,"line":8922},[3772,31525,31208],{"class":3980},[3772,31527,31528],{"class":3949},"locales",[3772,31530,4059],{"class":4272},[3772,31532,7562],{"class":3778},[3772,31534,6056],{"class":4272},[3772,31536,31537],{"class":3949},"l",[3772,31539,5765],{"class":4272},[3772,31541,5768],{"class":3980},[3772,31543,4213],{"class":4272},[3772,31545,31546,31548],{"class":3774,"line":8928},[3772,31547,31230],{"class":4218},[3772,31549,31233],{"class":4042},[3772,31551,31552,31554,31556,31558,31560,31562,31564],{"class":3774,"line":8934},[3772,31553,31238],{"class":4224},[3772,31555,4227],{"class":3945},[3772,31557,4230],{"class":3980},[3772,31559,31537],{"class":3949},[3772,31561,4059],{"class":4272},[3772,31563,5812],{"class":3949},[3772,31565,4316],{"class":3980},[3772,31567,31568,31570,31572,31574,31576,31578,31580,31582,31584,31586,31588,31590,31592,31594],{"class":3774,"line":8939},[3772,31569,31251],{"class":4224},[3772,31571,4227],{"class":3945},[3772,31573,4230],{"class":3980},[3772,31575,20154],{"class":4272},[3772,31577,5768],{"class":3980},[3772,31579,14600],{"class":3778},[3772,31581,5150],{"class":4272},[3772,31583,17696],{"class":3778},[3772,31585,5150],{"class":4272},[3772,31587,31537],{"class":3949},[3772,31589,4059],{"class":4272},[3772,31591,5812],{"class":3949},[3772,31593,31272],{"class":4272},[3772,31595,4316],{"class":3980},[3772,31597,31598,31600,31602,31604,31606,31608,31610,31612,31614,31616,31619,31621,31624,31626,31628,31630,31632,31634,31636,31638],{"class":3774,"line":8944},[3772,31599,31279],{"class":4224},[3772,31601,4227],{"class":3945},[3772,31603,4230],{"class":3980},[3772,31605,10793],{"class":4272},[3772,31607,30853],{"class":3949},[3772,31609,4059],{"class":4272},[3772,31611,31292],{"class":3949},[3772,31613,20886],{"class":4272},[3772,31615,30863],{"class":3949},[3772,31617,31618],{"class":3949}," locale",[3772,31620,31302],{"class":3945},[3772,31622,31623],{"class":3949}," l",[3772,31625,4059],{"class":4272},[3772,31627,5812],{"class":3949},[3772,31629,14788],{"class":3945},[3772,31631,31309],{"class":3781},[3772,31633,14794],{"class":3945},[3772,31635,30716],{"class":3949},[3772,31637,30868],{"class":4272},[3772,31639,4316],{"class":3980},[3772,31641,31642],{"class":3774,"line":8949},[3772,31643,31322],{"class":4218},[3772,31645,31646,31648,31650,31652,31654,31656,31658,31660,31662,31664,31666,31668,31670,31672,31674,31676,31678,31680,31682,31684,31686,31688],{"class":3774,"line":8955},[3772,31647,31327],{"class":4218},[3772,31649,14521],{"class":4042},[3772,31651,30844],{"class":4224},[3772,31653,4227],{"class":3945},[3772,31655,4230],{"class":3980},[3772,31657,4273],{"class":4272},[3772,31659,30897],{"class":3949},[3772,31661,31618],{"class":3949},[3772,31663,31302],{"class":3945},[3772,31665,31623],{"class":3949},[3772,31667,4059],{"class":4272},[3772,31669,5812],{"class":3949},[3772,31671,14788],{"class":3945},[3772,31673,31350],{"class":3781},[3772,31675,14794],{"class":3945},[3772,31677,30695],{"class":3949},[3772,31679,3847],{"class":4272},[3772,31681,31359],{"class":3949},[3772,31683,31362],{"class":3781},[3772,31685,4282],{"class":4272},[3772,31687,4235],{"class":3980},[3772,31689,4065],{"class":4218},[3772,31691,31692,31694,31696,31698,31700],{"class":3774,"line":8992},[3772,31693,31373],{"class":3980},[3772,31695,31537],{"class":3949},[3772,31697,4059],{"class":4272},[3772,31699,30777],{"class":3949},[3772,31701,4316],{"class":3980},[3772,31703,31704,31706,31708],{"class":3774,"line":9040},[3772,31705,31396],{"class":4218},[3772,31707,14521],{"class":4042},[3772,31709,4065],{"class":4218},[3772,31711,31712,31714,31716],{"class":3774,"line":9052},[3772,31713,31405],{"class":4218},[3772,31715,14516],{"class":4042},[3772,31717,4065],{"class":4218},[3772,31719,31720,31722],{"class":3774,"line":9077},[3772,31721,31414],{"class":4272},[3772,31723,4316],{"class":3980},[3772,31725,31726,31728,31730],{"class":3774,"line":9082},[3772,31727,31100],{"class":4218},[3772,31729,19205],{"class":4042},[3772,31731,4065],{"class":4218},[3772,31733,31734,31736,31738],{"class":3774,"line":9087},[3772,31735,4292],{"class":4218},[3772,31737,19205],{"class":4042},[3772,31739,4065],{"class":4218},[3772,31741,31742],{"class":3774,"line":9092},[3772,31743,3965],{"emptyLinePlaceholder":3964},[3772,31745,31746,31748,31750,31752,31754,31756,31758,31760,31762,31764],{"class":3774,"line":9098},[3772,31747,4242],{"class":4218},[3772,31749,19205],{"class":4042},[3772,31751,30844],{"class":4224},[3772,31753,4227],{"class":3945},[3772,31755,4230],{"class":3980},[3772,31757,30853],{"class":3949},[3772,31759,4059],{"class":4272},[3772,31761,31134],{"class":3949},[3772,31763,4235],{"class":3980},[3772,31765,4065],{"class":4218},[3772,31767,31768,31770],{"class":3774,"line":9121},[3772,31769,4251],{"class":4218},[3772,31771,31233],{"class":4042},[3772,31773,31774,31777,31779,31781,31783,31785,31787,31789,31791,31794],{"class":3774,"line":9166},[3772,31775,31776],{"class":4224},"                    onPress",[3772,31778,4227],{"class":3945},[3772,31780,4230],{"class":3980},[3772,31782,20154],{"class":4272},[3772,31784,5768],{"class":3980},[3772,31786,14600],{"class":3778},[3772,31788,5150],{"class":4272},[3772,31790,29789],{"class":3778},[3772,31792,31793],{"class":4272},"())",[3772,31795,4316],{"class":3980},[3772,31797,31798,31801,31803,31805,31807,31809,31811,31814,31816,31818,31820,31822],{"class":3774,"line":9171},[3772,31799,31800],{"class":4224},"                    style",[3772,31802,4227],{"class":3945},[3772,31804,4230],{"class":3980},[3772,31806,10793],{"class":4272},[3772,31808,30853],{"class":3949},[3772,31810,4059],{"class":4272},[3772,31812,31813],{"class":3949},"toggleButton",[3772,31815,20886],{"class":4272},[3772,31817,30863],{"class":3949},[3772,31819,30716],{"class":3949},[3772,31821,30868],{"class":4272},[3772,31823,4316],{"class":3980},[3772,31825,31826],{"class":3774,"line":9176},[3772,31827,31828],{"class":4218},"                >\n",[3772,31830,31831,31833,31835,31837,31839,31841,31843,31845,31847,31850,31852,31854,31856,31858,31860,31862,31865,31867,31869],{"class":3774,"line":9181},[3772,31832,30968],{"class":4218},[3772,31834,14521],{"class":4042},[3772,31836,30844],{"class":4224},[3772,31838,4227],{"class":3945},[3772,31840,4230],{"class":3980},[3772,31842,10793],{"class":4272},[3772,31844,30853],{"class":3949},[3772,31846,4059],{"class":4272},[3772,31848,31849],{"class":3949},"toggleText",[3772,31851,20886],{"class":4272},[3772,31853,30897],{"class":3949},[3772,31855,30695],{"class":3949},[3772,31857,30868],{"class":4272},[3772,31859,4235],{"class":3980},[3772,31861,14780],{"class":4218},[3772,31863,31864],{"class":3945},"Сповіщення",[3772,31866,14802],{"class":4218},[3772,31868,14521],{"class":4042},[3772,31870,4065],{"class":4218},[3772,31872,31873,31875,31877,31879,31881,31883,31885,31887,31890,31892,31895,31897,31900,31902,31904,31907,31909,31911],{"class":3774,"line":9187},[3772,31874,30968],{"class":4218},[3772,31876,14521],{"class":4042},[3772,31878,30844],{"class":4224},[3772,31880,4227],{"class":3945},[3772,31882,4230],{"class":3980},[3772,31884,4273],{"class":4272},[3772,31886,30897],{"class":3949},[3772,31888,31889],{"class":3949}," notificationsEnabled",[3772,31891,14788],{"class":3945},[3772,31893,31894],{"class":3781}," '#059669'",[3772,31896,14794],{"class":3945},[3772,31898,31899],{"class":3781}," '#dc2626'",[3772,31901,3847],{"class":4272},[3772,31903,31359],{"class":3949},[3772,31905,31906],{"class":3781}," '700'",[3772,31908,4282],{"class":4272},[3772,31910,4235],{"class":3980},[3772,31912,4065],{"class":4218},[3772,31914,31915,31918,31920,31922,31925,31927,31930],{"class":3774,"line":9206},[3772,31916,31917],{"class":3980},"                        {",[3772,31919,29739],{"class":3949},[3772,31921,14788],{"class":3945},[3772,31923,31924],{"class":3781}," 'УВІМКНЕНО'",[3772,31926,14794],{"class":3945},[3772,31928,31929],{"class":3781}," 'ВИМКНЕНО'",[3772,31931,4316],{"class":3980},[3772,31933,31934,31937,31939],{"class":3774,"line":9212},[3772,31935,31936],{"class":4218},"                    \u003C\u002F",[3772,31938,14521],{"class":4042},[3772,31940,4065],{"class":4218},[3772,31942,31943,31945,31947],{"class":3774,"line":9218},[3772,31944,31100],{"class":4218},[3772,31946,14516],{"class":4042},[3772,31948,4065],{"class":4218},[3772,31950,31951,31953,31955],{"class":3774,"line":9247},[3772,31952,4292],{"class":4218},[3772,31954,19205],{"class":4042},[3772,31956,4065],{"class":4218},[3772,31958,31959,31961,31963],{"class":3774,"line":9260},[3772,31960,4301],{"class":4218},[3772,31962,19205],{"class":4042},[3772,31964,4065],{"class":4218},[3772,31966,31967],{"class":3774,"line":9266},[3772,31968,4310],{"class":3945},[3772,31970,31971],{"class":3774,"line":9296},[3772,31972,4316],{"class":3945},[3772,31974,31975],{"class":3774,"line":9313},[3772,31976,3965],{"emptyLinePlaceholder":3964},[3772,31978,31979,31981,31984,31986,31988,31990,31993],{"class":3774,"line":9327},[3772,31980,5885],{"class":3980},[3772,31982,31983],{"class":3984}," styles",[3772,31985,3988],{"class":3945},[3772,31987,30491],{"class":3949},[3772,31989,4059],{"class":3945},[3772,31991,31992],{"class":3778},"create",[3772,31994,3993],{"class":3945},[3772,31996,31997,32000,32002,32005,32007,32009,32012,32014],{"class":3774,"line":9332},[3772,31998,31999],{"class":3949},"    container:",[3772,32001,3946],{"class":3945},[3772,32003,32004],{"class":3949},"flex:",[3772,32006,9815],{"class":8916},[3772,32008,3847],{"class":3945},[3772,32010,32011],{"class":3949},"padding:",[3772,32013,9825],{"class":8916},[3772,32015,4761],{"class":3945},[3772,32017,32018,32020,32022,32025,32028,32030,32032,32035,32037,32040,32042],{"class":3774,"line":9337},[3772,32019,28528],{"class":3949},[3772,32021,3946],{"class":3945},[3772,32023,32024],{"class":3949},"fontSize:",[3772,32026,32027],{"class":8916}," 28",[3772,32029,3847],{"class":3945},[3772,32031,31359],{"class":3949},[3772,32033,32034],{"class":3781}," '800'",[3772,32036,3847],{"class":3945},[3772,32038,32039],{"class":3949},"marginBottom:",[3772,32041,9825],{"class":8916},[3772,32043,4761],{"class":3945},[3772,32045,32046,32049,32051,32053,32056,32058,32061,32063,32065,32067,32070],{"class":3774,"line":9342},[3772,32047,32048],{"class":3949},"    userCard:",[3772,32050,3946],{"class":3945},[3772,32052,32011],{"class":3949},[3772,32054,32055],{"class":8916}," 16",[3772,32057,3847],{"class":3945},[3772,32059,32060],{"class":3949},"borderRadius:",[3772,32062,29990],{"class":8916},[3772,32064,3847],{"class":3945},[3772,32066,32039],{"class":3949},[3772,32068,32069],{"class":8916}," 24",[3772,32071,4761],{"class":3945},[3772,32073,32074,32077,32079,32081,32084,32086,32088,32090],{"class":3774,"line":9347},[3772,32075,32076],{"class":3949},"    userName:",[3772,32078,3946],{"class":3945},[3772,32080,32024],{"class":3949},[3772,32082,32083],{"class":8916}," 18",[3772,32085,3847],{"class":3945},[3772,32087,31359],{"class":3949},[3772,32089,31906],{"class":3781},[3772,32091,4761],{"class":3945},[3772,32093,32094,32097,32099,32101,32104,32106,32108,32111,32113,32116,32119],{"class":3774,"line":9353},[3772,32095,32096],{"class":3949},"    userEmail:",[3772,32098,3946],{"class":3945},[3772,32100,32024],{"class":3949},[3772,32102,32103],{"class":8916}," 13",[3772,32105,3847],{"class":3945},[3772,32107,30897],{"class":3949},[3772,32109,32110],{"class":3781}," '#64748b'",[3772,32112,3847],{"class":3945},[3772,32114,32115],{"class":3949},"marginTop:",[3772,32117,32118],{"class":8916}," 2",[3772,32120,4761],{"class":3945},[3772,32122,32123,32126,32128,32130,32132,32134,32136,32138,32140,32142,32144,32146,32148,32151],{"class":3774,"line":9391},[3772,32124,32125],{"class":3949},"    userTrips:",[3772,32127,3946],{"class":3945},[3772,32129,32024],{"class":3949},[3772,32131,32103],{"class":8916},[3772,32133,3847],{"class":3945},[3772,32135,30897],{"class":3949},[3772,32137,31309],{"class":3781},[3772,32139,3847],{"class":3945},[3772,32141,31359],{"class":3949},[3772,32143,31362],{"class":3781},[3772,32145,3847],{"class":3945},[3772,32147,32115],{"class":3949},[3772,32149,32150],{"class":8916}," 8",[3772,32152,4761],{"class":3945},[3772,32154,32155,32158,32160,32162,32164],{"class":3774,"line":9396},[3772,32156,32157],{"class":3949},"    section:",[3772,32159,3946],{"class":3945},[3772,32161,32039],{"class":3949},[3772,32163,9825],{"class":8916},[3772,32165,4761],{"class":3945},[3772,32167,32168,32171,32173,32175,32178,32180,32182,32184,32186,32188,32191],{"class":3774,"line":9402},[3772,32169,32170],{"class":3949},"    sectionTitle:",[3772,32172,3946],{"class":3945},[3772,32174,32024],{"class":3949},[3772,32176,32177],{"class":8916}," 15",[3772,32179,3847],{"class":3945},[3772,32181,31359],{"class":3949},[3772,32183,31362],{"class":3781},[3772,32185,3847],{"class":3945},[3772,32187,32039],{"class":3949},[3772,32189,32190],{"class":8916}," 10",[3772,32192,4761],{"class":3945},[3772,32194,32196,32199,32201,32204,32207,32209,32212,32214],{"class":3774,"line":32195},93,[3772,32197,32198],{"class":3949},"    row:",[3772,32200,3946],{"class":3945},[3772,32202,32203],{"class":3949},"flexDirection:",[3772,32205,32206],{"class":3781}," 'row'",[3772,32208,3847],{"class":3945},[3772,32210,32211],{"class":3949},"gap:",[3772,32213,32190],{"class":8916},[3772,32215,4761],{"class":3945},[3772,32217,32219,32222,32224,32227,32229,32231,32234,32236,32238,32240,32242],{"class":3774,"line":32218},94,[3772,32220,32221],{"class":3949},"    chip:",[3772,32223,3946],{"class":3945},[3772,32225,32226],{"class":3949},"paddingVertical:",[3772,32228,32190],{"class":8916},[3772,32230,3847],{"class":3945},[3772,32232,32233],{"class":3949},"paddingHorizontal:",[3772,32235,32055],{"class":8916},[3772,32237,3847],{"class":3945},[3772,32239,32060],{"class":3949},[3772,32241,32150],{"class":8916},[3772,32243,4761],{"class":3945},[3772,32245,32247,32250],{"class":3774,"line":32246},95,[3772,32248,32249],{"class":3949},"    toggleButton:",[3772,32251,4002],{"class":3945},[3772,32253,32255,32258,32260],{"class":3774,"line":32254},96,[3772,32256,32257],{"class":3949},"        flexDirection:",[3772,32259,32206],{"class":3781},[3772,32261,4806],{"class":3945},[3772,32263,32265,32268,32271],{"class":3774,"line":32264},97,[3772,32266,32267],{"class":3949},"        justifyContent:",[3772,32269,32270],{"class":3781}," 'space-between'",[3772,32272,4806],{"class":3945},[3772,32274,32276,32279,32282],{"class":3774,"line":32275},98,[3772,32277,32278],{"class":3949},"        alignItems:",[3772,32280,32281],{"class":3781}," 'center'",[3772,32283,4806],{"class":3945},[3772,32285,32287,32290,32292],{"class":3774,"line":32286},99,[3772,32288,32289],{"class":3949},"        padding:",[3772,32291,32055],{"class":8916},[3772,32293,4806],{"class":3945},[3772,32295,32297,32300,32302],{"class":3774,"line":32296},100,[3772,32298,32299],{"class":3949},"        borderRadius:",[3772,32301,29990],{"class":8916},[3772,32303,4806],{"class":3945},[3772,32305,32307],{"class":3774,"line":32306},101,[3772,32308,4014],{"class":3945},[3772,32310,32312,32315,32317,32319,32321,32323,32325,32327],{"class":3774,"line":32311},102,[3772,32313,32314],{"class":3949},"    toggleText:",[3772,32316,3946],{"class":3945},[3772,32318,32024],{"class":3949},[3772,32320,32177],{"class":8916},[3772,32322,3847],{"class":3945},[3772,32324,31359],{"class":3949},[3772,32326,31362],{"class":3781},[3772,32328,4761],{"class":3945},[3772,32330,32332],{"class":3774,"line":32331},103,[3772,32333,4020],{"class":3945},[3747,32335,32337,32338],{"id":32336},"крок-5-підключення-provider-у-apptsx","Крок 5. Підключення Provider у ",[3769,32339,29316],{},[3762,32341,32343],{"className":4129,"code":32342,"language":4131,"meta":3767,"style":3767},"\u002F\u002F App.tsx\nimport React from 'react'\nimport { SafeAreaView, StyleSheet } from 'react-native'\nimport { Provider } from 'react-redux'\nimport { store } from '.\u002Fsrc\u002Fstore'\nimport SettingsScreen from '.\u002Fsrc\u002Fscreens\u002FSettingsScreen'\n\nexport default function App() {\n    return (\n        \u003CProvider store={store}>\n            \u003CSafeAreaView style={styles.container}>\n                \u003CSettingsScreen \u002F>\n            \u003C\u002FSafeAreaView>\n        \u003C\u002FProvider>\n    )\n}\n\nconst styles = StyleSheet.create({\n    container: { flex: 1 },\n})\n",[3769,32344,32345,32349,32359,32378,32392,32406,32417,32421,32433,32439,32457,32479,32488,32496,32504,32508,32512,32516,32532,32544],{"__ignoreMap":3767},[3772,32346,32347],{"class":3774,"line":3775},[3772,32348,4329],{"class":3934},[3772,32350,32351,32353,32355,32357],{"class":3774,"line":3938},[3772,32352,3942],{"class":3941},[3772,32354,14502],{"class":3949},[3772,32356,6211],{"class":3941},[3772,32358,14507],{"class":3781},[3772,32360,32361,32363,32365,32368,32370,32372,32374,32376],{"class":3774,"line":3961},[3772,32362,3942],{"class":3941},[3772,32364,3946],{"class":3945},[3772,32366,32367],{"class":3949},"SafeAreaView",[3772,32369,3847],{"class":3945},[3772,32371,30491],{"class":3949},[3772,32373,3952],{"class":3945},[3772,32375,3955],{"class":3941},[3772,32377,14528],{"class":3781},[3772,32379,32380,32382,32384,32386,32388,32390],{"class":3774,"line":3968},[3772,32381,3942],{"class":3941},[3772,32383,3946],{"class":3945},[3772,32385,3865],{"class":3949},[3772,32387,3952],{"class":3945},[3772,32389,3955],{"class":3941},[3772,32391,4153],{"class":3781},[3772,32393,32394,32396,32398,32400,32402,32404],{"class":3774,"line":3974},[3772,32395,3942],{"class":3941},[3772,32397,3946],{"class":3945},[3772,32399,4162],{"class":3949},[3772,32401,3952],{"class":3945},[3772,32403,3955],{"class":3941},[3772,32405,4358],{"class":3781},[3772,32407,32408,32410,32412,32414],{"class":3774,"line":3996},[3772,32409,3942],{"class":3941},[3772,32411,30566],{"class":3949},[3772,32413,6211],{"class":3941},[3772,32415,32416],{"class":3781}," '.\u002Fsrc\u002Fscreens\u002FSettingsScreen'\n",[3772,32418,32419],{"class":3774,"line":4005},[3772,32420,3965],{"emptyLinePlaceholder":3964},[3772,32422,32423,32425,32427,32429,32431],{"class":3774,"line":4011},[3772,32424,3977],{"class":3941},[3772,32426,4196],{"class":3941},[3772,32428,4199],{"class":3980},[3772,32430,4405],{"class":3778},[3772,32432,4205],{"class":3945},[3772,32434,32435,32437],{"class":3774,"line":4017},[3772,32436,4210],{"class":3941},[3772,32438,4213],{"class":3945},[3772,32440,32441,32443,32445,32447,32449,32451,32453,32455],{"class":3774,"line":4023},[3772,32442,4219],{"class":4218},[3772,32444,3865],{"class":4042},[3772,32446,3985],{"class":4224},[3772,32448,4227],{"class":3945},[3772,32450,4230],{"class":3980},[3772,32452,4162],{"class":3949},[3772,32454,4235],{"class":3980},[3772,32456,4065],{"class":4218},[3772,32458,32459,32461,32463,32465,32467,32469,32471,32473,32475,32477],{"class":3774,"line":4028},[3772,32460,4242],{"class":4218},[3772,32462,32367],{"class":4042},[3772,32464,30844],{"class":4224},[3772,32466,4227],{"class":3945},[3772,32468,4230],{"class":3980},[3772,32470,30853],{"class":3949},[3772,32472,4059],{"class":4272},[3772,32474,30858],{"class":3949},[3772,32476,4235],{"class":3980},[3772,32478,4065],{"class":4218},[3772,32480,32481,32483,32486],{"class":3774,"line":4034},[3772,32482,4251],{"class":4218},[3772,32484,32485],{"class":4042},"SettingsScreen",[3772,32487,4287],{"class":4218},[3772,32489,32490,32492,32494],{"class":3774,"line":4068},[3772,32491,4292],{"class":4218},[3772,32493,32367],{"class":4042},[3772,32495,4065],{"class":4218},[3772,32497,32498,32500,32502],{"class":3774,"line":4313},[3772,32499,4301],{"class":4218},[3772,32501,3865],{"class":4042},[3772,32503,4065],{"class":4218},[3772,32505,32506],{"class":3774,"line":4470},[3772,32507,4310],{"class":3945},[3772,32509,32510],{"class":3774,"line":4879},[3772,32511,4316],{"class":3945},[3772,32513,32514],{"class":3774,"line":4892},[3772,32515,3965],{"emptyLinePlaceholder":3964},[3772,32517,32518,32520,32522,32524,32526,32528,32530],{"class":3774,"line":4903},[3772,32519,5885],{"class":3980},[3772,32521,31983],{"class":3984},[3772,32523,3988],{"class":3945},[3772,32525,30491],{"class":3949},[3772,32527,4059],{"class":3945},[3772,32529,31992],{"class":3778},[3772,32531,3993],{"class":3945},[3772,32533,32534,32536,32538,32540,32542],{"class":3774,"line":4909},[3772,32535,31999],{"class":3949},[3772,32537,3946],{"class":3945},[3772,32539,32004],{"class":3949},[3772,32541,9815],{"class":8916},[3772,32543,4761],{"class":3945},[3772,32545,32546],{"class":3774,"line":5521},[3772,32547,4020],{"class":3945},[4495,32549],{},[3738,32551,32553],{"id":32552},"наскрізний-проєкт-nomad","Наскрізний проєкт: Nomad",[3743,32555,32556],{},"Тепер інтегруємо Redux Toolkit у щоденник подорожей Nomad для централізованого керування поїздками, стану асинхронного завантаження та фільтрації.",[3747,32558,32560],{"id":32559},"_1-асинхронний-thunk-завантаження-поїздок","1. Асинхронний Thunk завантаження поїздок",[3762,32562,32564],{"className":3925,"code":32563,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fthunks\u002FtripsThunks.ts\nimport { createAsyncThunk } from '@reduxjs\u002Ftoolkit'\nimport { apiClient } from '@\u002Fapi\u002Fclient'\nimport { AppError } from '@\u002Fapi\u002FAppError'\nimport type { Trip } from '@\u002Ffeatures\u002Ftrips\u002Ftypes'\n\nexport const fetchTripsThunk = createAsyncThunk\u003CTrip[], void, { rejectValue: string }>(\n    'trips\u002FfetchTrips',\n    async (_, { rejectWithValue }) => {\n        try {\n            const response = await apiClient.get\u003CTrip[]>('\u002Ftrips')\n            return response.data\n        } catch (error) {\n            const appError = AppError.from(error)\n            return rejectWithValue(appError.userMessage)\n        }\n    },\n)\n",[3769,32565,32566,32570,32584,32598,32612,32628,32632,32662,32668,32686,32692,32718,32728,32740,32760,32776,32780,32784],{"__ignoreMap":3767},[3772,32567,32568],{"class":3774,"line":3775},[3772,32569,21840],{"class":3934},[3772,32571,32572,32574,32576,32578,32580,32582],{"class":3774,"line":3938},[3772,32573,3942],{"class":3941},[3772,32575,3946],{"class":3945},[3772,32577,3853],{"class":3949},[3772,32579,3952],{"class":3945},[3772,32581,3955],{"class":3941},[3772,32583,3958],{"class":3781},[3772,32585,32586,32588,32590,32592,32594,32596],{"class":3774,"line":3961},[3772,32587,3942],{"class":3941},[3772,32589,3946],{"class":3945},[3772,32591,14944],{"class":3949},[3772,32593,3952],{"class":3945},[3772,32595,3955],{"class":3941},[3772,32597,14951],{"class":3781},[3772,32599,32600,32602,32604,32606,32608,32610],{"class":3774,"line":3968},[3772,32601,3942],{"class":3941},[3772,32603,3946],{"class":3945},[3772,32605,24792],{"class":3949},[3772,32607,3952],{"class":3945},[3772,32609,3955],{"class":3941},[3772,32611,24799],{"class":3781},[3772,32613,32614,32616,32618,32620,32622,32624,32626],{"class":3774,"line":3974},[3772,32615,3942],{"class":3941},[3772,32617,4039],{"class":3941},[3772,32619,3946],{"class":3945},[3772,32621,6436],{"class":3949},[3772,32623,3952],{"class":3945},[3772,32625,3955],{"class":3941},[3772,32627,24840],{"class":3781},[3772,32629,32630],{"class":3774,"line":3996},[3772,32631,3965],{"emptyLinePlaceholder":3964},[3772,32633,32634,32636,32638,32640,32642,32644,32646,32648,32650,32652,32654,32656,32658,32660],{"class":3774,"line":4005},[3772,32635,3977],{"class":3941},[3772,32637,3981],{"class":3980},[3772,32639,21958],{"class":3984},[3772,32641,3988],{"class":3945},[3772,32643,3853],{"class":3778},[3772,32645,4051],{"class":3945},[3772,32647,6436],{"class":4042},[3772,32649,21971],{"class":3945},[3772,32651,24397],{"class":4042},[3772,32653,20886],{"class":3945},[3772,32655,21999],{"class":3949},[3772,32657,4800],{"class":3945},[3772,32659,6459],{"class":4042},[3772,32661,24413],{"class":3945},[3772,32663,32664,32666],{"class":3774,"line":4011},[3772,32665,20103],{"class":3781},[3772,32667,4806],{"class":3945},[3772,32669,32670,32672,32674,32676,32678,32680,32682,32684],{"class":3774,"line":4017},[3772,32671,16746],{"class":3980},[3772,32673,5179],{"class":3945},[3772,32675,24691],{"class":3949},[3772,32677,20886],{"class":3945},[3772,32679,15099],{"class":3949},[3772,32681,15102],{"class":3945},[3772,32683,5768],{"class":3980},[3772,32685,4002],{"class":3945},[3772,32687,32688,32690],{"class":3774,"line":4023},[3772,32689,20679],{"class":3941},[3772,32691,4002],{"class":3945},[3772,32693,32694,32696,32698,32700,32702,32704,32706,32708,32710,32712,32714,32716],{"class":3774,"line":4028},[3772,32695,8995],{"class":3980},[3772,32697,15161],{"class":3984},[3772,32699,3988],{"class":3945},[3772,32701,15166],{"class":3941},[3772,32703,15169],{"class":3949},[3772,32705,4059],{"class":3945},[3772,32707,22201],{"class":3778},[3772,32709,4051],{"class":3945},[3772,32711,6436],{"class":4042},[3772,32713,24056],{"class":3945},[3772,32715,22642],{"class":3781},[3772,32717,5345],{"class":3945},[3772,32719,32720,32722,32724,32726],{"class":3774,"line":4034},[3772,32721,5977],{"class":3941},[3772,32723,15161],{"class":3949},[3772,32725,4059],{"class":3945},[3772,32727,16789],{"class":3949},[3772,32729,32730,32732,32734,32736,32738],{"class":3774,"line":4068},[3772,32731,20813],{"class":3945},[3772,32733,15259],{"class":3941},[3772,32735,5179],{"class":3945},[3772,32737,5072],{"class":3949},[3772,32739,5166],{"class":3945},[3772,32741,32742,32744,32746,32748,32750,32752,32754,32756,32758],{"class":3774,"line":4313},[3772,32743,8995],{"class":3980},[3772,32745,25026],{"class":3984},[3772,32747,3988],{"class":3945},[3772,32749,24792],{"class":3949},[3772,32751,4059],{"class":3945},[3772,32753,3955],{"class":3778},[3772,32755,5150],{"class":3945},[3772,32757,5072],{"class":3949},[3772,32759,5345],{"class":3945},[3772,32761,32762,32764,32766,32768,32770,32772,32774],{"class":3774,"line":4470},[3772,32763,5977],{"class":3941},[3772,32765,15277],{"class":3778},[3772,32767,5150],{"class":3945},[3772,32769,25051],{"class":3949},[3772,32771,4059],{"class":3945},[3772,32773,25056],{"class":3949},[3772,32775,5345],{"class":3945},[3772,32777,32778],{"class":3774,"line":4879},[3772,32779,5245],{"class":3945},[3772,32781,32782],{"class":3774,"line":4892},[3772,32783,4014],{"class":3945},[3772,32785,32786],{"class":3774,"line":4903},[3772,32787,5345],{"class":3945},[3747,32789,32791,32792],{"id":32790},"_2-створення-tripsslice","2. Створення ",[3769,32793,6804],{},[3762,32795,32797],{"className":3925,"code":32796,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fslices\u002FtripsSlice.ts\nimport { createSlice, PayloadAction } from '@reduxjs\u002Ftoolkit'\nimport type { Trip } from '@\u002Ffeatures\u002Ftrips\u002Ftypes'\nimport { fetchTripsThunk } from '..\u002Fthunks\u002FtripsThunks'\n\ninterface TripsState {\n    items: Trip[]\n    loading: boolean\n    error: string | null\n}\n\nconst initialState: TripsState = {\n    items: [],\n    loading: false,\n    error: null,\n}\n\nexport const tripsSlice = createSlice({\n    name: 'trips',\n    initialState,\n    reducers: {\n        addTrip(state, action: PayloadAction\u003CTrip>) {\n            state.items.unshift(action.payload)\n        },\n        removeTrip(state, action: PayloadAction\u003Cstring>) {\n            state.items = state.items.filter((trip) => trip.id !== action.payload)\n        },\n        clearTripsError(state) {\n            state.error = null\n        },\n    },\n    extraReducers: (builder) => {\n        builder\n            .addCase(fetchTripsThunk.pending, (state) => {\n                state.loading = true\n                state.error = null\n            })\n            .addCase(fetchTripsThunk.fulfilled, (state, action) => {\n                state.items = action.payload\n                state.loading = false\n                state.error = null\n            })\n            .addCase(fetchTripsThunk.rejected, (state, action) => {\n                state.loading = false\n                state.error = action.payload ?? 'Не вдалося завантажити поїздки'\n            })\n    },\n})\n\nexport const { addTrip, removeTrip, clearTripsError } = tripsSlice.actions\nexport default tripsSlice.reducer\n",[3769,32798,32799,32803,32821,32837,32851,32855,32863,32873,32881,32893,32897,32901,32913,32919,32927,32935,32939,32943,32957,32965,32971,32977,32999,33021,33025,33047,33091,33095,33106,33118,33122,33126,33142,33146,33170,33182,33194,33198,33226,33242,33254,33266,33270,33298,33310,33330,33334,33338,33342,33346,33372],{"__ignoreMap":3767},[3772,32800,32801],{"class":3774,"line":3775},[3772,32802,6348],{"class":3934},[3772,32804,32805,32807,32809,32811,32813,32815,32817,32819],{"class":3774,"line":3938},[3772,32806,3942],{"class":3941},[3772,32808,3946],{"class":3945},[3772,32810,3846],{"class":3949},[3772,32812,3847],{"class":3945},[3772,32814,6361],{"class":3949},[3772,32816,3952],{"class":3945},[3772,32818,3955],{"class":3941},[3772,32820,3958],{"class":3781},[3772,32822,32823,32825,32827,32829,32831,32833,32835],{"class":3774,"line":3961},[3772,32824,3942],{"class":3941},[3772,32826,4039],{"class":3941},[3772,32828,3946],{"class":3945},[3772,32830,6436],{"class":3949},[3772,32832,3952],{"class":3945},[3772,32834,3955],{"class":3941},[3772,32836,24840],{"class":3781},[3772,32838,32839,32841,32843,32845,32847,32849],{"class":3774,"line":3968},[3772,32840,3942],{"class":3941},[3772,32842,3946],{"class":3945},[3772,32844,9229],{"class":3949},[3772,32846,3952],{"class":3945},[3772,32848,3955],{"class":3941},[3772,32850,11983],{"class":3781},[3772,32852,32853],{"class":3774,"line":3974},[3772,32854,3965],{"emptyLinePlaceholder":3964},[3772,32856,32857,32859,32861],{"class":3774,"line":3996},[3772,32858,6376],{"class":3980},[3772,32860,6424],{"class":4042},[3772,32862,4002],{"class":3945},[3772,32864,32865,32867,32869,32871],{"class":3774,"line":4005},[3772,32866,6431],{"class":3949},[3772,32868,4800],{"class":3945},[3772,32870,6436],{"class":4042},[3772,32872,6439],{"class":3945},[3772,32874,32875,32877,32879],{"class":3774,"line":4011},[3772,32876,6444],{"class":3949},[3772,32878,4800],{"class":3945},[3772,32880,6449],{"class":4042},[3772,32882,32883,32885,32887,32889,32891],{"class":3774,"line":4017},[3772,32884,6454],{"class":3949},[3772,32886,4800],{"class":3945},[3772,32888,6459],{"class":4042},[3772,32890,6462],{"class":3945},[3772,32892,4816],{"class":4042},[3772,32894,32895],{"class":3774,"line":4023},[3772,32896,4316],{"class":3945},[3772,32898,32899],{"class":3774,"line":4028},[3772,32900,3965],{"emptyLinePlaceholder":3964},[3772,32902,32903,32905,32907,32909,32911],{"class":3774,"line":4034},[3772,32904,5885],{"class":3980},[3772,32906,5888],{"class":3984},[3772,32908,4800],{"class":3945},[3772,32910,6483],{"class":4042},[3772,32912,5891],{"class":3945},[3772,32914,32915,32917],{"class":3774,"line":4068},[3772,32916,5385],{"class":3949},[3772,32918,5898],{"class":3945},[3772,32920,32921,32923,32925],{"class":3774,"line":4313},[3772,32922,5903],{"class":3949},[3772,32924,4279],{"class":3980},[3772,32926,4806],{"class":3945},[3772,32928,32929,32931,32933],{"class":3774,"line":4470},[3772,32930,5912],{"class":3949},[3772,32932,5915],{"class":3980},[3772,32934,4806],{"class":3945},[3772,32936,32937],{"class":3774,"line":4879},[3772,32938,4316],{"class":3945},[3772,32940,32941],{"class":3774,"line":4892},[3772,32942,3965],{"emptyLinePlaceholder":3964},[3772,32944,32945,32947,32949,32951,32953,32955],{"class":3774,"line":4903},[3772,32946,3977],{"class":3941},[3772,32948,3981],{"class":3980},[3772,32950,6529],{"class":3984},[3772,32952,3988],{"class":3945},[3772,32954,3846],{"class":3778},[3772,32956,3993],{"class":3945},[3772,32958,32959,32961,32963],{"class":3774,"line":4909},[3772,32960,6540],{"class":3949},[3772,32962,6543],{"class":3781},[3772,32964,4806],{"class":3945},[3772,32966,32967,32969],{"class":3774,"line":5521},[3772,32968,6550],{"class":3949},[3772,32970,4806],{"class":3945},[3772,32972,32973,32975],{"class":3774,"line":5527},[3772,32974,6557],{"class":3949},[3772,32976,4002],{"class":3945},[3772,32978,32979,32981,32983,32985,32987,32989,32991,32993,32995,32997],{"class":3774,"line":5533},[3772,32980,6569],{"class":3778},[3772,32982,5150],{"class":3945},[3772,32984,5153],{"class":3949},[3772,32986,3847],{"class":3945},[3772,32988,5163],{"class":3949},[3772,32990,4800],{"class":3945},[3772,32992,6361],{"class":4042},[3772,32994,4051],{"class":3945},[3772,32996,6436],{"class":4042},[3772,32998,6588],{"class":3945},[3772,33000,33001,33003,33005,33007,33009,33011,33013,33015,33017,33019],{"class":3774,"line":5539},[3772,33002,6598],{"class":3949},[3772,33004,4059],{"class":3945},[3772,33006,5237],{"class":3949},[3772,33008,4059],{"class":3945},[3772,33010,8757],{"class":3778},[3772,33012,5150],{"class":3945},[3772,33014,5163],{"class":3949},[3772,33016,4059],{"class":3945},[3772,33018,5059],{"class":3949},[3772,33020,5345],{"class":3945},[3772,33022,33023],{"class":3774,"line":5545},[3772,33024,6621],{"class":3945},[3772,33026,33027,33029,33031,33033,33035,33037,33039,33041,33043,33045],{"class":3774,"line":5550},[3772,33028,6632],{"class":3778},[3772,33030,5150],{"class":3945},[3772,33032,5153],{"class":3949},[3772,33034,3847],{"class":3945},[3772,33036,5163],{"class":3949},[3772,33038,4800],{"class":3945},[3772,33040,6361],{"class":4042},[3772,33042,4051],{"class":3945},[3772,33044,6459],{"class":4042},[3772,33046,6588],{"class":3945},[3772,33048,33049,33051,33053,33055,33057,33059,33061,33063,33065,33067,33069,33071,33073,33075,33077,33079,33081,33083,33085,33087,33089],{"class":3774,"line":6121},[3772,33050,6598],{"class":3949},[3772,33052,4059],{"class":3945},[3772,33054,5237],{"class":3949},[3772,33056,3988],{"class":3945},[3772,33058,5153],{"class":3949},[3772,33060,4059],{"class":3945},[3772,33062,5237],{"class":3949},[3772,33064,4059],{"class":3945},[3772,33066,6053],{"class":3778},[3772,33068,6056],{"class":3945},[3772,33070,5762],{"class":3949},[3772,33072,5765],{"class":3945},[3772,33074,5768],{"class":3980},[3772,33076,5788],{"class":3949},[3772,33078,4059],{"class":3945},[3772,33080,5812],{"class":3949},[3772,33082,6073],{"class":3945},[3772,33084,5163],{"class":3949},[3772,33086,4059],{"class":3945},[3772,33088,5059],{"class":3949},[3772,33090,5345],{"class":3945},[3772,33092,33093],{"class":3774,"line":6131},[3772,33094,6621],{"class":3945},[3772,33096,33097,33100,33102,33104],{"class":3774,"line":6136},[3772,33098,33099],{"class":3778},"        clearTripsError",[3772,33101,5150],{"class":3945},[3772,33103,5153],{"class":3949},[3772,33105,5166],{"class":3945},[3772,33107,33108,33110,33112,33114,33116],{"class":3774,"line":6142},[3772,33109,6598],{"class":3949},[3772,33111,4059],{"class":3945},[3772,33113,5072],{"class":3949},[3772,33115,3988],{"class":3945},[3772,33117,4816],{"class":3980},[3772,33119,33120],{"class":3774,"line":6150},[3772,33121,6621],{"class":3945},[3772,33123,33124],{"class":3774,"line":6157},[3772,33125,4014],{"class":3945},[3772,33127,33128,33130,33132,33134,33136,33138,33140],{"class":3774,"line":6162},[3772,33129,9190],{"class":3778},[3772,33131,4094],{"class":3949},[3772,33133,5179],{"class":3945},[3772,33135,9197],{"class":3949},[3772,33137,5765],{"class":3945},[3772,33139,5768],{"class":3980},[3772,33141,4002],{"class":3945},[3772,33143,33144],{"class":3774,"line":6629},[3772,33145,9215],{"class":3949},[3772,33147,33148,33150,33152,33154,33156,33158,33160,33162,33164,33166,33168],{"class":3774,"line":6653},[3772,33149,9221],{"class":3945},[3772,33151,9224],{"class":3778},[3772,33153,5150],{"class":3945},[3772,33155,9229],{"class":3949},[3772,33157,4059],{"class":3945},[3772,33159,9234],{"class":3949},[3772,33161,7128],{"class":3945},[3772,33163,5153],{"class":3949},[3772,33165,5765],{"class":3945},[3772,33167,5768],{"class":3980},[3772,33169,4002],{"class":3945},[3772,33171,33172,33174,33176,33178,33180],{"class":3774,"line":6698},[3772,33173,8815],{"class":3949},[3772,33175,4059],{"class":3945},[3772,33177,6741],{"class":3949},[3772,33179,3988],{"class":3945},[3772,33181,4865],{"class":3980},[3772,33183,33184,33186,33188,33190,33192],{"class":3774,"line":6703},[3772,33185,8815],{"class":3949},[3772,33187,4059],{"class":3945},[3772,33189,5072],{"class":3949},[3772,33191,3988],{"class":3945},[3772,33193,4816],{"class":3980},[3772,33195,33196],{"class":3774,"line":6709},[3772,33197,9263],{"class":3945},[3772,33199,33200,33202,33204,33206,33208,33210,33212,33214,33216,33218,33220,33222,33224],{"class":3774,"line":6734},[3772,33201,9221],{"class":3945},[3772,33203,9224],{"class":3778},[3772,33205,5150],{"class":3945},[3772,33207,9229],{"class":3949},[3772,33209,4059],{"class":3945},[3772,33211,9279],{"class":3949},[3772,33213,7128],{"class":3945},[3772,33215,5153],{"class":3949},[3772,33217,3847],{"class":3945},[3772,33219,5163],{"class":3949},[3772,33221,5765],{"class":3945},[3772,33223,5768],{"class":3980},[3772,33225,4002],{"class":3945},[3772,33227,33228,33230,33232,33234,33236,33238,33240],{"class":3774,"line":6753},[3772,33229,8815],{"class":3949},[3772,33231,4059],{"class":3945},[3772,33233,5237],{"class":3949},[3772,33235,3988],{"class":3945},[3772,33237,5163],{"class":3949},[3772,33239,4059],{"class":3945},[3772,33241,6750],{"class":3949},[3772,33243,33244,33246,33248,33250,33252],{"class":3774,"line":6758},[3772,33245,8815],{"class":3949},[3772,33247,4059],{"class":3945},[3772,33249,6741],{"class":3949},[3772,33251,3988],{"class":3945},[3772,33253,9324],{"class":3980},[3772,33255,33256,33258,33260,33262,33264],{"class":3774,"line":6763},[3772,33257,8815],{"class":3949},[3772,33259,4059],{"class":3945},[3772,33261,5072],{"class":3949},[3772,33263,3988],{"class":3945},[3772,33265,4816],{"class":3980},[3772,33267,33268],{"class":3774,"line":6768},[3772,33269,9263],{"class":3945},[3772,33271,33272,33274,33276,33278,33280,33282,33284,33286,33288,33290,33292,33294,33296],{"class":3774,"line":6773},[3772,33273,9221],{"class":3945},[3772,33275,9224],{"class":3778},[3772,33277,5150],{"class":3945},[3772,33279,9229],{"class":3949},[3772,33281,4059],{"class":3945},[3772,33283,12260],{"class":3949},[3772,33285,7128],{"class":3945},[3772,33287,5153],{"class":3949},[3772,33289,3847],{"class":3945},[3772,33291,5163],{"class":3949},[3772,33293,5765],{"class":3945},[3772,33295,5768],{"class":3980},[3772,33297,4002],{"class":3945},[3772,33299,33300,33302,33304,33306,33308],{"class":3774,"line":6779},[3772,33301,8815],{"class":3949},[3772,33303,4059],{"class":3945},[3772,33305,6741],{"class":3949},[3772,33307,3988],{"class":3945},[3772,33309,9324],{"class":3980},[3772,33311,33312,33314,33316,33318,33320,33322,33324,33326,33328],{"class":3774,"line":6812},[3772,33313,8815],{"class":3949},[3772,33315,4059],{"class":3945},[3772,33317,5072],{"class":3949},[3772,33319,3988],{"class":3945},[3772,33321,5163],{"class":3949},[3772,33323,4059],{"class":3945},[3772,33325,5059],{"class":3949},[3772,33327,12305],{"class":3945},[3772,33329,25795],{"class":3781},[3772,33331,33332],{"class":3774,"line":6817},[3772,33333,9263],{"class":3945},[3772,33335,33336],{"class":3774,"line":6823},[3772,33337,4014],{"class":3945},[3772,33339,33340],{"class":3774,"line":8841},[3772,33341,4020],{"class":3945},[3772,33343,33344],{"class":3774,"line":8865},[3772,33345,3965],{"emptyLinePlaceholder":3964},[3772,33347,33348,33350,33352,33354,33356,33358,33360,33362,33364,33366,33368,33370],{"class":3774,"line":8873},[3772,33349,3977],{"class":3941},[3772,33351,3981],{"class":3980},[3772,33353,3946],{"class":3945},[3772,33355,6788],{"class":3984},[3772,33357,3847],{"class":3945},[3772,33359,6793],{"class":3984},[3772,33361,3847],{"class":3945},[3772,33363,28812],{"class":3984},[3772,33365,6801],{"class":3945},[3772,33367,6804],{"class":3949},[3772,33369,4059],{"class":3945},[3772,33371,6809],{"class":3949},[3772,33373,33374,33376,33378,33380,33382],{"class":3774,"line":8881},[3772,33375,3977],{"class":3941},[3772,33377,4196],{"class":3941},[3772,33379,6529],{"class":3949},[3772,33381,4059],{"class":3945},[3772,33383,6834],{"class":3949},[3747,33385,33387],{"id":33386},"_3-мемоїзовані-селектори-поїздок","3. Мемоїзовані селектори поїздок",[3762,33389,33391],{"className":3925,"code":33390,"language":3927,"meta":3767,"style":3767},"\u002F\u002F src\u002Fstore\u002Fselectors\u002FtripsSelectors.ts\nimport { createSelector } from '@reduxjs\u002Ftoolkit'\nimport type { RootState } from '..\u002Findex'\n\nexport const selectTripsState = (state: RootState) => state.trips\n\nexport const selectAllTrips = createSelector([selectTripsState], (tripsState) => tripsState.items)\n\nexport const selectTripsLoading = createSelector([selectTripsState], (tripsState) => tripsState.loading)\n\nexport const selectTripsError = createSelector([selectTripsState], (tripsState) => tripsState.error)\n\nexport const selectTripById = (tripId: string) =>\n    createSelector([selectAllTrips], (trips) => trips.find((trip) => trip.id === tripId))\n",[3769,33392,33393,33398,33412,33428,33432,33459,33463,33499,33503,33536,33540,33573,33577,33597],{"__ignoreMap":3767},[3772,33394,33395],{"class":3774,"line":3775},[3772,33396,33397],{"class":3934},"\u002F\u002F src\u002Fstore\u002Fselectors\u002FtripsSelectors.ts\n",[3772,33399,33400,33402,33404,33406,33408,33410],{"class":3774,"line":3938},[3772,33401,3942],{"class":3941},[3772,33403,3946],{"class":3945},[3772,33405,16461],{"class":3949},[3772,33407,3952],{"class":3945},[3772,33409,3955],{"class":3941},[3772,33411,3958],{"class":3781},[3772,33413,33414,33416,33418,33420,33422,33424,33426],{"class":3774,"line":3961},[3772,33415,3942],{"class":3941},[3772,33417,4039],{"class":3941},[3772,33419,3946],{"class":3945},[3772,33421,14962],{"class":3949},[3772,33423,3952],{"class":3945},[3772,33425,3955],{"class":3941},[3772,33427,14969],{"class":3781},[3772,33429,33430],{"class":3774,"line":3968},[3772,33431,3965],{"emptyLinePlaceholder":3964},[3772,33433,33434,33436,33438,33441,33443,33445,33447,33449,33451,33453,33455,33457],{"class":3774,"line":3974},[3772,33435,3977],{"class":3941},[3772,33437,3981],{"class":3980},[3772,33439,33440],{"class":3778}," selectTripsState",[3772,33442,5759],{"class":3945},[3772,33444,5153],{"class":3949},[3772,33446,4800],{"class":3945},[3772,33448,14962],{"class":4042},[3772,33450,5765],{"class":3945},[3772,33452,5768],{"class":3980},[3772,33454,5353],{"class":3949},[3772,33456,4059],{"class":3945},[3772,33458,20911],{"class":3949},[3772,33460,33461],{"class":3774,"line":3996},[3772,33462,3965],{"emptyLinePlaceholder":3964},[3772,33464,33465,33467,33469,33472,33474,33476,33478,33481,33483,33486,33488,33490,33493,33495,33497],{"class":3774,"line":4005},[3772,33466,3977],{"class":3941},[3772,33468,3981],{"class":3980},[3772,33470,33471],{"class":3984}," selectAllTrips",[3772,33473,3988],{"class":3945},[3772,33475,16461],{"class":3778},[3772,33477,18629],{"class":3945},[3772,33479,33480],{"class":3949},"selectTripsState",[3772,33482,16483],{"class":3945},[3772,33484,33485],{"class":3949},"tripsState",[3772,33487,5765],{"class":3945},[3772,33489,5768],{"class":3980},[3772,33491,33492],{"class":3949}," tripsState",[3772,33494,4059],{"class":3945},[3772,33496,5237],{"class":3949},[3772,33498,5345],{"class":3945},[3772,33500,33501],{"class":3774,"line":4011},[3772,33502,3965],{"emptyLinePlaceholder":3964},[3772,33504,33505,33507,33509,33512,33514,33516,33518,33520,33522,33524,33526,33528,33530,33532,33534],{"class":3774,"line":4017},[3772,33506,3977],{"class":3941},[3772,33508,3981],{"class":3980},[3772,33510,33511],{"class":3984}," selectTripsLoading",[3772,33513,3988],{"class":3945},[3772,33515,16461],{"class":3778},[3772,33517,18629],{"class":3945},[3772,33519,33480],{"class":3949},[3772,33521,16483],{"class":3945},[3772,33523,33485],{"class":3949},[3772,33525,5765],{"class":3945},[3772,33527,5768],{"class":3980},[3772,33529,33492],{"class":3949},[3772,33531,4059],{"class":3945},[3772,33533,6741],{"class":3949},[3772,33535,5345],{"class":3945},[3772,33537,33538],{"class":3774,"line":4023},[3772,33539,3965],{"emptyLinePlaceholder":3964},[3772,33541,33542,33544,33546,33549,33551,33553,33555,33557,33559,33561,33563,33565,33567,33569,33571],{"class":3774,"line":4028},[3772,33543,3977],{"class":3941},[3772,33545,3981],{"class":3980},[3772,33547,33548],{"class":3984}," selectTripsError",[3772,33550,3988],{"class":3945},[3772,33552,16461],{"class":3778},[3772,33554,18629],{"class":3945},[3772,33556,33480],{"class":3949},[3772,33558,16483],{"class":3945},[3772,33560,33485],{"class":3949},[3772,33562,5765],{"class":3945},[3772,33564,5768],{"class":3980},[3772,33566,33492],{"class":3949},[3772,33568,4059],{"class":3945},[3772,33570,5072],{"class":3949},[3772,33572,5345],{"class":3945},[3772,33574,33575],{"class":3774,"line":4034},[3772,33576,3965],{"emptyLinePlaceholder":3964},[3772,33578,33579,33581,33583,33585,33587,33589,33591,33593,33595],{"class":3774,"line":4068},[3772,33580,3977],{"class":3941},[3772,33582,3981],{"class":3980},[3772,33584,18609],{"class":3778},[3772,33586,5759],{"class":3945},[3772,33588,7598],{"class":3949},[3772,33590,4800],{"class":3945},[3772,33592,6459],{"class":4042},[3772,33594,5765],{"class":3945},[3772,33596,11064],{"class":3980},[3772,33598,33599,33601,33603,33605,33607,33609,33611,33613,33615,33617,33619,33621,33623,33625,33627,33629,33631,33633,33635,33637],{"class":3774,"line":4313},[3772,33600,18626],{"class":3778},[3772,33602,18629],{"class":3945},[3772,33604,26926],{"class":3949},[3772,33606,16483],{"class":3945},[3772,33608,7557],{"class":3949},[3772,33610,5765],{"class":3945},[3772,33612,5768],{"class":3980},[3772,33614,10947],{"class":3949},[3772,33616,4059],{"class":3945},[3772,33618,7856],{"class":3778},[3772,33620,6056],{"class":3945},[3772,33622,5762],{"class":3949},[3772,33624,5765],{"class":3945},[3772,33626,5768],{"class":3980},[3772,33628,5788],{"class":3949},[3772,33630,4059],{"class":3945},[3772,33632,5812],{"class":3949},[3772,33634,5188],{"class":3945},[3772,33636,7598],{"class":3949},[3772,33638,10331],{"class":3945},[3747,33640,33642,33643],{"id":33641},"_4-підключення-redux-до-кореневого-макета-app_layouttsx","4. Підключення Redux до кореневого макета ",[3769,33644,33645],{},"app\u002F_layout.tsx",[3762,33647,33649],{"className":4129,"code":33648,"language":4131,"meta":3767,"style":3767},"\u002F\u002F app\u002F_layout.tsx\nimport React from 'react'\nimport { Stack } from 'expo-router'\nimport { StatusBar } from 'expo-status-bar'\nimport { Provider } from 'react-redux'\nimport { store } from '@\u002Fstore'\nimport { OfflineBanner } from '@\u002Fcomponents\u002FOfflineBanner'\nimport { ThemeProvider, useTheme } from '@\u002Fshared\u002Ftheme'\n\nfunction RootNavigator() {\n    const { colors, scheme } = useTheme()\n\n    return (\n        \u003C>\n            \u003CStatusBar style={scheme === 'dark' ? 'light' : 'dark'} \u002F>\n            \u003COfflineBanner \u002F>\n            \u003CStack\n                screenOptions={{\n                    contentStyle: { backgroundColor: colors.background },\n                    headerStyle: { backgroundColor: colors.background },\n                    headerTintColor: colors.primary,\n                    headerTitleStyle: { color: colors.text, fontWeight: '600' },\n                    headerShadowVisible: false,\n                }}\n            >\n                \u003CStack.Screen name=\"(tabs)\" options={{ headerShown: false }} \u002F>\n                \u003CStack.Screen\n                    name=\"create-trip\"\n                    options={{\n                        headerShown: true,\n                        title: 'Нова поїздка',\n                        presentation: 'modal',\n                        headerBackTitle: 'Закрити',\n                    }}\n                \u002F>\n            \u003C\u002FStack>\n        \u003C\u002F>\n    )\n}\n\nexport default function RootLayout() {\n    return (\n        \u003CProvider store={store}>\n            \u003CThemeProvider>\n                \u003CRootNavigator \u002F>\n            \u003C\u002FThemeProvider>\n        \u003C\u002FProvider>\n    )\n}\n",[3769,33650,33651,33655,33665,33679,33695,33709,33723,33739,33760,33764,33773,33793,33797,33803,33808,33839,33847,33854,33865,33884,33901,33915,33938,33947,33954,33959,33989,33996,34006,34017,34026,34036,34046,34056,34063,34068,34076,34081,34085,34089,34093,34105,34111,34129,34137,34145,34153,34161,34165],{"__ignoreMap":3767},[3772,33652,33653],{"class":3774,"line":3775},[3772,33654,4138],{"class":3934},[3772,33656,33657,33659,33661,33663],{"class":3774,"line":3938},[3772,33658,3942],{"class":3941},[3772,33660,14502],{"class":3949},[3772,33662,6211],{"class":3941},[3772,33664,14507],{"class":3781},[3772,33666,33667,33669,33671,33673,33675,33677],{"class":3774,"line":3961},[3772,33668,3942],{"class":3941},[3772,33670,3946],{"class":3945},[3772,33672,4178],{"class":3949},[3772,33674,3952],{"class":3945},[3772,33676,3955],{"class":3941},[3772,33678,4185],{"class":3781},[3772,33680,33681,33683,33685,33688,33690,33692],{"class":3774,"line":3968},[3772,33682,3942],{"class":3941},[3772,33684,3946],{"class":3945},[3772,33686,33687],{"class":3949},"StatusBar",[3772,33689,3952],{"class":3945},[3772,33691,3955],{"class":3941},[3772,33693,33694],{"class":3781}," 'expo-status-bar'\n",[3772,33696,33697,33699,33701,33703,33705,33707],{"class":3774,"line":3974},[3772,33698,3942],{"class":3941},[3772,33700,3946],{"class":3945},[3772,33702,3865],{"class":3949},[3772,33704,3952],{"class":3945},[3772,33706,3955],{"class":3941},[3772,33708,4153],{"class":3781},[3772,33710,33711,33713,33715,33717,33719,33721],{"class":3774,"line":3996},[3772,33712,3942],{"class":3941},[3772,33714,3946],{"class":3945},[3772,33716,4162],{"class":3949},[3772,33718,3952],{"class":3945},[3772,33720,3955],{"class":3941},[3772,33722,4169],{"class":3781},[3772,33724,33725,33727,33729,33732,33734,33736],{"class":3774,"line":4005},[3772,33726,3942],{"class":3941},[3772,33728,3946],{"class":3945},[3772,33730,33731],{"class":3949},"OfflineBanner",[3772,33733,3952],{"class":3945},[3772,33735,3955],{"class":3941},[3772,33737,33738],{"class":3781}," '@\u002Fcomponents\u002FOfflineBanner'\n",[3772,33740,33741,33743,33745,33748,33750,33753,33755,33757],{"class":3774,"line":4011},[3772,33742,3942],{"class":3941},[3772,33744,3946],{"class":3945},[3772,33746,33747],{"class":3949},"ThemeProvider",[3772,33749,3847],{"class":3945},[3772,33751,33752],{"class":3949},"useTheme",[3772,33754,3952],{"class":3945},[3772,33756,3955],{"class":3941},[3772,33758,33759],{"class":3781}," '@\u002Fshared\u002Ftheme'\n",[3772,33761,33762],{"class":3774,"line":4017},[3772,33763,3965],{"emptyLinePlaceholder":3964},[3772,33765,33766,33768,33771],{"class":3774,"line":4023},[3772,33767,5144],{"class":3980},[3772,33769,33770],{"class":3778}," RootNavigator",[3772,33772,4205],{"class":3945},[3772,33774,33775,33777,33779,33782,33784,33787,33789,33791],{"class":3774,"line":4028},[3772,33776,10944],{"class":3980},[3772,33778,3946],{"class":3945},[3772,33780,33781],{"class":3984},"colors",[3772,33783,3847],{"class":3945},[3772,33785,33786],{"class":3984},"scheme",[3772,33788,6801],{"class":3945},[3772,33790,33752],{"class":3778},[3772,33792,13941],{"class":3945},[3772,33794,33795],{"class":3774,"line":4034},[3772,33796,3965],{"emptyLinePlaceholder":3964},[3772,33798,33799,33801],{"class":3774,"line":4068},[3772,33800,4210],{"class":3941},[3772,33802,4213],{"class":3945},[3772,33804,33805],{"class":3774,"line":4313},[3772,33806,33807],{"class":4218},"        \u003C>\n",[3772,33809,33810,33812,33814,33816,33818,33820,33822,33824,33827,33829,33831,33833,33835,33837],{"class":3774,"line":4470},[3772,33811,4242],{"class":4218},[3772,33813,33687],{"class":4042},[3772,33815,30844],{"class":4224},[3772,33817,4227],{"class":3945},[3772,33819,4230],{"class":3980},[3772,33821,33786],{"class":3949},[3772,33823,31302],{"class":3945},[3772,33825,33826],{"class":3781}," 'dark'",[3772,33828,14788],{"class":3945},[3772,33830,29518],{"class":3781},[3772,33832,14794],{"class":3945},[3772,33834,33826],{"class":3781},[3772,33836,4235],{"class":3980},[3772,33838,4287],{"class":4218},[3772,33840,33841,33843,33845],{"class":3774,"line":4879},[3772,33842,4242],{"class":4218},[3772,33844,33731],{"class":4042},[3772,33846,4287],{"class":4218},[3772,33848,33849,33851],{"class":3774,"line":4892},[3772,33850,4242],{"class":4218},[3772,33852,33853],{"class":4042},"Stack\n",[3772,33855,33856,33859,33861,33863],{"class":3774,"line":4903},[3772,33857,33858],{"class":4224},"                screenOptions",[3772,33860,4227],{"class":3945},[3772,33862,4230],{"class":3980},[3772,33864,4714],{"class":4272},[3772,33866,33867,33870,33872,33874,33877,33879,33882],{"class":3774,"line":4909},[3772,33868,33869],{"class":3949},"                    contentStyle:",[3772,33871,3946],{"class":4272},[3772,33873,30863],{"class":3949},[3772,33875,33876],{"class":3949}," colors",[3772,33878,4059],{"class":4272},[3772,33880,33881],{"class":3949},"background",[3772,33883,4761],{"class":4272},[3772,33885,33886,33889,33891,33893,33895,33897,33899],{"class":3774,"line":5521},[3772,33887,33888],{"class":3949},"                    headerStyle:",[3772,33890,3946],{"class":4272},[3772,33892,30863],{"class":3949},[3772,33894,33876],{"class":3949},[3772,33896,4059],{"class":4272},[3772,33898,33881],{"class":3949},[3772,33900,4761],{"class":4272},[3772,33902,33903,33906,33908,33910,33913],{"class":3774,"line":5527},[3772,33904,33905],{"class":3949},"                    headerTintColor:",[3772,33907,33876],{"class":3949},[3772,33909,4059],{"class":4272},[3772,33911,33912],{"class":3949},"primary",[3772,33914,4806],{"class":4272},[3772,33916,33917,33920,33922,33924,33926,33928,33930,33932,33934,33936],{"class":3774,"line":5533},[3772,33918,33919],{"class":3949},"                    headerTitleStyle:",[3772,33921,3946],{"class":4272},[3772,33923,30897],{"class":3949},[3772,33925,33876],{"class":3949},[3772,33927,4059],{"class":4272},[3772,33929,3910],{"class":3949},[3772,33931,3847],{"class":4272},[3772,33933,31359],{"class":3949},[3772,33935,31362],{"class":3781},[3772,33937,4761],{"class":4272},[3772,33939,33940,33943,33945],{"class":3774,"line":5539},[3772,33941,33942],{"class":3949},"                    headerShadowVisible:",[3772,33944,4279],{"class":3980},[3772,33946,4806],{"class":4272},[3772,33948,33949,33952],{"class":3774,"line":5545},[3772,33950,33951],{"class":4272},"                }",[3772,33953,4316],{"class":3980},[3772,33955,33956],{"class":3774,"line":5550},[3772,33957,33958],{"class":4218},"            >\n",[3772,33960,33961,33963,33965,33967,33969,33971,33973,33975,33977,33979,33981,33983,33985,33987],{"class":3774,"line":6121},[3772,33962,4251],{"class":4218},[3772,33964,4254],{"class":4042},[3772,33966,4257],{"class":4224},[3772,33968,4227],{"class":3945},[3772,33970,4262],{"class":3781},[3772,33972,4265],{"class":4224},[3772,33974,4227],{"class":3945},[3772,33976,4230],{"class":3980},[3772,33978,4273],{"class":4272},[3772,33980,4276],{"class":3949},[3772,33982,4279],{"class":3980},[3772,33984,4282],{"class":4272},[3772,33986,4235],{"class":3980},[3772,33988,4287],{"class":4218},[3772,33990,33991,33993],{"class":3774,"line":6131},[3772,33992,4251],{"class":4218},[3772,33994,33995],{"class":4042},"Stack.Screen\n",[3772,33997,33998,34001,34003],{"class":3774,"line":6136},[3772,33999,34000],{"class":4224},"                    name",[3772,34002,4227],{"class":3945},[3772,34004,34005],{"class":3781},"\"create-trip\"\n",[3772,34007,34008,34011,34013,34015],{"class":3774,"line":6142},[3772,34009,34010],{"class":4224},"                    options",[3772,34012,4227],{"class":3945},[3772,34014,4230],{"class":3980},[3772,34016,4714],{"class":4272},[3772,34018,34019,34022,34024],{"class":3774,"line":6150},[3772,34020,34021],{"class":3949},"                        headerShown:",[3772,34023,6116],{"class":3980},[3772,34025,4806],{"class":4272},[3772,34027,34028,34031,34034],{"class":3774,"line":6157},[3772,34029,34030],{"class":3949},"                        title:",[3772,34032,34033],{"class":3781}," 'Нова поїздка'",[3772,34035,4806],{"class":4272},[3772,34037,34038,34041,34044],{"class":3774,"line":6162},[3772,34039,34040],{"class":3949},"                        presentation:",[3772,34042,34043],{"class":3781}," 'modal'",[3772,34045,4806],{"class":4272},[3772,34047,34048,34051,34054],{"class":3774,"line":6629},[3772,34049,34050],{"class":3949},"                        headerBackTitle:",[3772,34052,34053],{"class":3781}," 'Закрити'",[3772,34055,4806],{"class":4272},[3772,34057,34058,34061],{"class":3774,"line":6653},[3772,34059,34060],{"class":4272},"                    }",[3772,34062,4316],{"class":3980},[3772,34064,34065],{"class":3774,"line":6698},[3772,34066,34067],{"class":4218},"                \u002F>\n",[3772,34069,34070,34072,34074],{"class":3774,"line":6703},[3772,34071,4292],{"class":4218},[3772,34073,4178],{"class":4042},[3772,34075,4065],{"class":4218},[3772,34077,34078],{"class":3774,"line":6709},[3772,34079,34080],{"class":4218},"        \u003C\u002F>\n",[3772,34082,34083],{"class":3774,"line":6734},[3772,34084,4310],{"class":3945},[3772,34086,34087],{"class":3774,"line":6753},[3772,34088,4316],{"class":3945},[3772,34090,34091],{"class":3774,"line":6758},[3772,34092,3965],{"emptyLinePlaceholder":3964},[3772,34094,34095,34097,34099,34101,34103],{"class":3774,"line":6763},[3772,34096,3977],{"class":3941},[3772,34098,4196],{"class":3941},[3772,34100,4199],{"class":3980},[3772,34102,4202],{"class":3778},[3772,34104,4205],{"class":3945},[3772,34106,34107,34109],{"class":3774,"line":6768},[3772,34108,4210],{"class":3941},[3772,34110,4213],{"class":3945},[3772,34112,34113,34115,34117,34119,34121,34123,34125,34127],{"class":3774,"line":6773},[3772,34114,4219],{"class":4218},[3772,34116,3865],{"class":4042},[3772,34118,3985],{"class":4224},[3772,34120,4227],{"class":3945},[3772,34122,4230],{"class":3980},[3772,34124,4162],{"class":3949},[3772,34126,4235],{"class":3980},[3772,34128,4065],{"class":4218},[3772,34130,34131,34133,34135],{"class":3774,"line":6779},[3772,34132,4242],{"class":4218},[3772,34134,33747],{"class":4042},[3772,34136,4065],{"class":4218},[3772,34138,34139,34141,34143],{"class":3774,"line":6812},[3772,34140,4251],{"class":4218},[3772,34142,4383],{"class":4042},[3772,34144,4287],{"class":4218},[3772,34146,34147,34149,34151],{"class":3774,"line":6817},[3772,34148,4292],{"class":4218},[3772,34150,33747],{"class":4042},[3772,34152,4065],{"class":4218},[3772,34154,34155,34157,34159],{"class":3774,"line":6823},[3772,34156,4301],{"class":4218},[3772,34158,3865],{"class":4042},[3772,34160,4065],{"class":4218},[3772,34162,34163],{"class":3774,"line":8841},[3772,34164,4310],{"class":3945},[3772,34166,34167],{"class":3774,"line":8865},[3772,34168,4316],{"class":3945},[4495,34170],{},[3738,34172,34174],{"id":34173},"резюме-розділу","Резюме розділу",[34176,34177,34178,34191,34199,34204],"card-group",{},[34179,34180,34182,34184,34185,34187,34188,34190],"card",{"icon":943,"title":34181},"🏗️ Архітектура Store та Slice",[3769,34183,3850],{}," автоматично створює сховище з ",[3769,34186,4105],{},", DevTools та валідацією серіалізованості. ",[3769,34189,3846],{}," генерує редюсери та творці дій без зайвого коду.",[34179,34192,34195,34196,34198],{"icon":34193,"title":34194},"i-lucide-sparkles","⚡ Механіка Immer Proxy","Immer використовує механізм ",[3769,34197,7774],{}," для безпечного перетворення мутуючого коду всередині редюсера на новий іммутабельний стан за принципом Copy-on-Write.",[34179,34200,34203],{"icon":34201,"title":34202},"i-lucide-file-json","📦 Сувора Серіалізованість","Зберігайте лише JSON-сумісні типи. Дати представляйте у вигляді ISO 8601 рядків або Unix timestamp для безпечного збереження на диск та дебагу.",[34179,34205,9867,34208,34210],{"icon":34206,"title":34207},"i-lucide-filter","🎯 Reselect Мемоїзація",[3769,34209,16461],{}," для захисту мобільних компонентів від повторних рендерингів при обчисленні похідних даних.",[4495,34212],{},[3738,34214,34216],{"id":34215},"практичні-завдання","Практичні завдання",[12405,34218,34219,34232],{},[12408,34220,34221],{},[12411,34222,34223,34226,34229],{},[12414,34224,34225],{"align":27450},"Рівень складності",[12414,34227,34228],{"align":27450},"Назва завдання",[12414,34230,34231],{"align":27450},"Формулювання вимог",[12426,34233,34234,34257,34277],{},[12411,34235,34236,34241,34244],{},[12431,34237,34238],{"align":27450},[3829,34239,34240],{},"Базовий (Basic)",[12431,34242,34243],{"align":27450},"Фільтрація поїздок за регіоном",[12431,34245,34246,34247,34250,34251,34253,34254,4059],{"align":27450},"Створити селектор ",[3769,34248,34249],{},"selectTripsByRegion(region: string)"," за допомогою ",[3769,34252,16461],{},". Підключити Picker або горизонтальний список чіпів для фільтрації списку на екрані ",[3769,34255,34256],{},"(tabs)\u002Ftrips\u002Findex.tsx",[12411,34258,34259,34264,34267],{},[12431,34260,34261],{"align":27450},[3829,34262,34263],{},"Середній (Intermediate)",[12431,34265,34266],{"align":27450},"Оптимістичний лайк з Rollback",[12431,34268,34269,34270,34273,34274,34276],{"align":27450},"Реалізувати слайс ",[3769,34271,34272],{},"likesSlice"," та thunk ",[3769,34275,28056],{},", що миттєво оновлює стан сердечка у стрічці, а при помилці мережі виконує автоматичний відкат значення.",[12411,34278,34279,34284,34289],{},[12431,34280,34281],{"align":27450},[3829,34282,34283],{},"Просунутий (Advanced)",[12431,34285,34286,34287],{"align":27450},"Персистентність на базі ",[3769,34288,17614],{},[12431,34290,34291,34292,34294,34295,9546,34298,34301],{"align":27450},"Створити слухач через ",[3769,34293,17614],{},", який при кожній дії з префіксом ",[3769,34296,34297],{},"settings\u002F",[3769,34299,34300],{},"trips\u002F"," асинхронно записує актуальний JSON-стан у швидке локальне сховище MMKV.",[4495,34303],{},[3738,34305,34307],{"id":34306},"поширені-запитання-faq","Поширені запитання (FAQ)",[10844,34309,34310,34327,34337,34358],{},[10847,34311,34313,34314,4479,34316,34319,34320,34322,34323,34326],{"icon":10849,"label":34312},"Чому не можна мутувати state за межами createSlice?","Immer перехоплює мутації через ",[3769,34315,7774],{},[3829,34317,34318],{},"лише всередині функцій reducers",", переданих у ",[3769,34321,3846],{},". Якщо ви мутуєте стан у компоненті, селекторі або thunk (наприклад, ",[3769,34324,34325],{},"trips.push(...)","), ви безпосередньо ламаєте іммутабельність об'єкта, що призведе до пропуску рендерингу в React та непередбачуваних багів.",[10847,34328,34330,34332,34333,34336],{"icon":92,"label":34329},"Чим createListenerMiddleware кращий за Redux-Saga у React Native?",[3769,34331,17614],{}," вбудований у Redux Toolkit, має крихітний розмір (~2.5 КБ), повністю підтримує async\u002Fawait, не вимагає генераторів ",[3769,34334,34335],{},"function*"," і на відміну від Saga забезпечує 100% точну типізацію TypeScript з коробки.",[10847,34338,34341,34343,34344,3847,34346,3847,34348,34350,34351,34353,34354,8279,34356,4059],{"icon":34339,"label":34340},"i-lucide-git-pull-request","Чим createAsyncThunk відрізняється від звичайного виклику API у useEffect?",[3769,34342,3853],{}," стандартизує асинхронний життєвий цикл (",[3769,34345,9234],{},[3769,34347,9279],{},[3769,34349,12260],{},"), автоматично диспатчить відповідні дії, дозволяє обробляти стан завантаження глобально в store, підтримує перевірку ",[3769,34352,27366],{}," (захист від дублікатів) та скасування запитів через ",[3769,34355,20721],{},[3769,34357,27369],{},[10847,34359,34361],{"icon":13761,"label":34360},"Чи замінює Redux Toolkit повністю React Context?","Ні. Для простого, локального стану з рідкісними змінами (наприклад, стан поточної теми UI або системні налаштування доступності) React Context є відмінним легковаговим рішенням. Redux Toolkit застосовується там, де є складні бізнес-дані, асинхронні запити, часті оновлення та потреба в інспектуванні через DevTools.",[34363,34364,34365],"style",{},"html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .s-QsJ, html code.shiki .s-QsJ{--shiki-light:#0070C1;--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s0P7L, html code.shiki .s0P7L{--shiki-light:#800000;--shiki-default:#808080;--shiki-dark:#808080}html pre.shiki code .sa4r_, html code.shiki .sa4r_{--shiki-light:#E50000;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .s5IvJ, html code.shiki .s5IvJ{--shiki-light:#000000;--shiki-default:#C8C8C8;--shiki-dark:#C8C8C8}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}",{"title":3767,"searchDepth":3938,"depth":3938,"links":34367},[34368,34374,34375,34378,34384,34388,34396,34417,34423,34426,34427,34432,34433,34434,34445,34453,34454,34455],{"id":3740,"depth":3938,"text":3741,"children":34369},[34370,34371,34372,34373],{"id":3749,"depth":3961,"text":3750},{"id":3900,"depth":3961,"text":3901},{"id":3918,"depth":3961,"text":3919},{"id":4115,"depth":3961,"text":4116},{"id":4499,"depth":3938,"text":4500},{"id":4578,"depth":3938,"text":4579,"children":34376},[34377],{"id":4582,"depth":3961,"text":4583},{"id":4681,"depth":3938,"text":4682,"children":34379},[34380,34381,34382,34383],{"id":4688,"depth":3961,"text":4689},{"id":4941,"depth":3961,"text":4942},{"id":5111,"depth":3961,"text":5112},{"id":5411,"depth":3961,"text":5412},{"id":5613,"depth":3938,"text":5614,"children":34385},[34386,34387],{"id":5620,"depth":3961,"text":2199},{"id":6330,"depth":3961,"text":6331},{"id":6917,"depth":3938,"text":6918,"children":34389},[34390,34391,34392,34394],{"id":6924,"depth":3961,"text":6925},{"id":7416,"depth":3961,"text":7417},{"id":8357,"depth":3961,"text":34393},"3. Slice (createSlice): Повний розбір",{"id":14454,"depth":3961,"text":34395},"4. Store (configureStore) та конвеєр Middleware",{"id":14474,"depth":3938,"text":14475,"children":34397},[34398,34399,34400,34401,34402,34403,34404,34405,34407,34409,34411,34413,34415],{"id":14484,"depth":3961,"text":14485},{"id":14825,"depth":3961,"text":14826},{"id":14910,"depth":3961,"text":14911},{"id":15307,"depth":3961,"text":15308},{"id":15983,"depth":3961,"text":15984},{"id":16127,"depth":3961,"text":16128},{"id":16360,"depth":3961,"text":16361},{"id":16883,"depth":3961,"text":34406},"4. Store (configureStore) та конвеєр Middleware (продовження)",{"id":17610,"depth":3961,"text":34408},"5. Сучасні легковагі сайд-ефекти: createListenerMiddleware",{"id":18094,"depth":3961,"text":34410},"6. Селектори та мемоїзація за допомогою createSelector (Reselect)",{"id":18900,"depth":3961,"text":34412},"7. Типізовані хуки: useAppDispatch та useAppSelector",{"id":19248,"depth":3961,"text":34414},"8. Нормалізація стану за допомогою createEntityAdapter",{"id":19850,"depth":3961,"text":34416},"9. Асинхронні операції: createAsyncThunk у деталях",{"id":26171,"depth":3938,"text":26172,"children":34418},[34419,34420,34421,34422],{"id":26175,"depth":3961,"text":26176},{"id":26207,"depth":3961,"text":26208},{"id":26661,"depth":3961,"text":26662},{"id":26859,"depth":3961,"text":26860},{"id":27301,"depth":3938,"text":27302,"children":34424},[34425],{"id":27440,"depth":3961,"text":27441},{"id":27601,"depth":3938,"text":27602},{"id":28308,"depth":3938,"text":28309,"children":34428},[34429,34430,34431],{"id":28323,"depth":3961,"text":28324},{"id":28404,"depth":3961,"text":28405},{"id":28438,"depth":3961,"text":28439},{"id":28783,"depth":3938,"text":28784},{"id":29116,"depth":3938,"text":29117},{"id":29246,"depth":3938,"text":29247,"children":34435},[34436,34437,34438,34439,34441,34442,34443],{"id":29272,"depth":3961,"text":29273},{"id":29321,"depth":3961,"text":29322},{"id":29328,"depth":3961,"text":29329},{"id":29372,"depth":3961,"text":34440},"Крок 2. Створення settingsSlice та userSlice",{"id":30200,"depth":3961,"text":30201},{"id":30449,"depth":3961,"text":30450},{"id":32336,"depth":3961,"text":34444},"Крок 5. Підключення Provider у App.tsx",{"id":32552,"depth":3938,"text":32553,"children":34446},[34447,34448,34450,34451],{"id":32559,"depth":3961,"text":32560},{"id":32790,"depth":3961,"text":34449},"2. Створення tripsSlice",{"id":33386,"depth":3961,"text":33387},{"id":33641,"depth":3961,"text":34452},"4. Підключення Redux до кореневого макета app\u002F_layout.tsx",{"id":34173,"depth":3938,"text":34174},{"id":34215,"depth":3938,"text":34216},{"id":34306,"depth":3938,"text":34307},"Повний практичний посібник з Redux Toolkit у React Native — будова Store, Slice, Reducer, Action, createListenerMiddleware, персистентність з MMKV, оптимістичні оновлення, скасування thunk через AbortController, createEntityAdapter, Reselect мемоїзація та тестування логіки.","md",null,{},{"title":3448,"description":34456},"uzzz2c6KGInNi87ev4SlNJ3yqgv_OPzwNFawRTnZh0c",[34463,34465],{"title":3444,"path":3445,"stem":3446,"description":34464,"children":-1},"Глибокий практичний розбір мережевого стека React Native (fetch, axios, нативні стеки NSURLSession та OkHttpClient), нормалізація серверного стану, класифікація та обробка помилок, експоненційний backoff з jitter, черги оновлення токенів, моніторинг з'єднання через NetInfo та керування життєвим циклом застосунку через AppState.",{"title":3452,"path":3453,"stem":3454,"description":34466,"children":-1},"Практичний навчальний посібник з RTK Query у React Native — від простих прикладів до складних сценаріїв. Дізнайтеся як автоматизувати роботу з серверними даними, налаштувати кеш, інвалідацію та оптимістичні оновлення у мобільному застосунку.",1788069964297]