### Install Zedux React Package Source: https://zedux.dev/walkthrough/quick-start This snippet provides commands for installing the `@zedux/react` package, which bundles core Zedux functionalities and React-specific APIs. It supports npm, yarn, and pnpm, and requires React version 18 or higher as a peer dependency. ```bash npm install @zedux/react # npm yarn add @zedux/react # yarn pnpm add @zedux/react # pnpm ``` -------------------------------- ### Zedux Todo List Example with Atoms and React Hooks Source: https://zedux.dev/walkthrough/quick-start This comprehensive example illustrates how to define and utilize Zedux atoms for state management within a React application. It demonstrates the creation of stateful atoms using `atom()`, dependency injection between atoms with `injectAtomState()`, and consumption of atom state in React components via `useAtomState()`. The example sets up a basic todo list that filters tasks into 'finished' and 'unfinished' categories. ```TypeScript const todosAtom = atom('todos', () => [ { text: 'Go', isDone: true }, { text: 'Fight', isDone: true }, { text: 'Win', isDone: false }, ]) const filteredTodosAtom = atom('filteredTodos', (isDone: boolean) => { const [todos] = injectAtomState(todosAtom) const filteredTodos = todos.filter(todo => todo.isDone === isDone) return filteredTodos.map(({ text }) => text) }) // These 2 components pass different params to the filteredTodos atom: function FinishedTodos() { const [todos] = useAtomState(filteredTodosAtom, [true]) return
Finished Todos: {todos.join`, `}
} function UnfinishedTodos() { const [todos] = useAtomState(filteredTodosAtom, [false]) return
Unfinished Todos: {todos.join`, `}
} const Todos = () => ( <> ) ``` -------------------------------- ### Create a Zero-Config Zedux Store Source: https://zedux.dev/walkthrough/stores Demonstrates how to initialize a basic Zedux store without any configuration, using the `createStore` function from the `@zedux/react` package. This is the simplest way to get started with Zedux stores. ```javascript import { createStore } from '@zedux/react' const easySauceStore = createStore() ``` -------------------------------- ### Define a Basic Zedux Atom Template Source: https://zedux.dev/walkthrough/quick-start Illustrates the creation of an atom template using the `atom()` factory from `@zedux/react`. Atom templates serve as blueprints, defining a unique key and an initial value for state, from which Zedux automatically instantiates atoms. ```javascript import { atom } from '@zedux/react' const greetingAtom = atom('greeting', 'Hello, world!') ``` -------------------------------- ### Share Atom State Across Components with Caching Source: https://zedux.dev/walkthrough/quick-start Illustrates how Zedux caches atom instances, allowing multiple components to reuse the same atom template and share its state. This example shows two components, one for displaying and one for editing, both connected to the same `greetingAtom`, demonstrating state synchronization. ```JavaScript const greetingAtom = atom('greeting', 'Hello, world!') function GreetingPreview() { const [greeting] = useAtomState(greetingAtom) return
The greeting: {greeting}
} function EditGreeting() { const [greeting, setGreeting] = useAtomState(greetingAtom) return ( setGreeting(target.value)} value={greeting} /> ) } const Greeting = () => ( <> ) ``` -------------------------------- ### Define Atom State with a Factory Function Source: https://zedux.dev/walkthrough/quick-start Shows how to use a factory function as the second parameter to `atom()` to dynamically create the initial state of an atom instance. This pattern is useful for more complex state initialization logic that might depend on other factors or require computation. ```JavaScript const helloAtom = atom('hello', () => 'world') ``` -------------------------------- ### Example of Injecting Custom Configured Zedux Stores Source: https://zedux.dev/walkthrough/stores Provides a conceptual example of how custom injectors might return configured Zedux stores, setting the stage for scenarios where store composition becomes useful. ```javascript const storeA = injectMyConfiguredStore() const storeB = injectAnotherFancyStore() ``` -------------------------------- ### Migrate from injectStore to injectSignal Source: https://zedux.dev/migrations/v2 Illustrates the core change for incremental migration from store-based atoms to signals, showing how `injectStore`, `getState`, and `setState` are replaced by `injectSignal`, `get`, and `set` respectively. ```JavaScript // before: import { storeApi as api, storeAtom as atom, injectStore } from '@zedux/stores' // after: import { api, atom, injectSignal } from '@zedux/react' // replace `injectStore` with `injectSignal` // replace `store.getState` with `signal.get` // replace `store.setState` with `signal.set` // replace `store.setStateDeep` with `signal.mutate` ``` -------------------------------- ### Examples of createEcosystem Function Usage Source: https://zedux.dev/api/factories/createEcosystem This section provides practical examples of how to use the `createEcosystem` function. It covers basic instantiation with an ID, configuring an ecosystem with atom overrides, and utilizing the `onReady` callback to perform actions like preloading atoms immediately after ecosystem creation. ```TypeScript import { createEcosystem } from '@zedux/react' const rootEcosystem = createEcosystem({ id: 'root' }) const withOverrides = createEcosystem({ id: 'withOverrides', overrides: [atomA, atomB], }) const withOnReadyFn = createEcosystem({ id: 'withOnReadyFn', onReady: ecosystem => { // `onReady` is passed a reference to the ecosystem ecosystem.getInstance(myAtom) // preload myAtom }, }) ``` -------------------------------- ### Zedux Signal State Mutation and Observation Source: https://zedux.dev/migrations/v2 This example demonstrates how to create a Zedux signal, mutate its state using `signal.mutate`, and observe these mutations by subscribing to the 'mutate' event. It shows how state updates are handled through transactions. ```JavaScript const ecosystem = createEcosystem() const signal = ecosystem.signal({ foo: 'bar', baz: [{ whateverIsAfterBaz: 1 }], }) signal.on('mutate', transactions => { // uncomment this and open browser console: // console.log('got transactions:', transactions) }) signal.mutate(state => { state.foo = 'bar none' }) signal.mutate(state => { state.baz[0].whateverIsAfterBaz++ }) const state = signal.get() ``` -------------------------------- ### Usage Examples for `get` Function Source: https://zedux.dev/api/types/AtomGetters Demonstrates various ways to use the `get` function to retrieve the current state of an atom instance, accepting an atom template, a template with parameters, or a direct atom instance. ```JavaScript value = get(myAtom) value = get(myAtom, [param1, param2]) value = get(myAtomInstance) ``` -------------------------------- ### Full Theme Toggle MachineStore Example with React Source: https://zedux.dev/packages/machines/injectMachineStore A comprehensive example showcasing `injectMachineStore` to implement a theme toggle state machine. It defines 'light' and 'dark' states, handles 'toggle' events, and updates a context counter on each transition. The example integrates this machine with a React component using `useAtomState` to control UI elements and display machine state and context. ```typescript const themeAtom = atom('theme', () => { const store = injectMachineStore( state => [ state('light').on('toggle', 'dark'), state('dark').on('toggle', 'light'), ], { count: 0 }, { onTransition: machine => machine.setContext(context => ({ count: context.count + 1 })), } ) return api(store).setExports({ send: store.send }) }) function Theme() { const [{ context, value }, { send }] = useAtomState(themeAtom) return (
Toggle Count: {context.count}
) ``` -------------------------------- ### Inject Atom State for Inter-Atom Dependencies Source: https://zedux.dev/walkthrough/quick-start Explains how atoms can depend on other atoms by injecting their state using `injectAtomState()`. This allows for building complex state graphs where one atom's state is derived from another's, promoting modularity and reusability within the atom ecosystem. ```JavaScript import { atom, injectAtomState } from '@zedux/react' const textAtom = atom('text', 'World') const loudGreetingAtom = atom('loudGreeting', () => { const [text] = injectAtomState(textAtom) return `HELLO, ${text.toUpperCase()}` }) ``` -------------------------------- ### Zedux Store Method: use Usage Examples Source: https://zedux.dev/api/classes/Store Provides examples of how to use the `use` method to dynamically change a store's composition, including replacing and merging hierarchies. ```JavaScript const myStore = createStore(rootReducer) // the initial "hierarchy" myStore.use(anotherStore) // completely replace the store's state myStore.use({ // completely replace the store's state a: storeA, b: storeB, }) myStore.use({ // merge this hierarchy into the previous hierarchy b: null, // remove "b" from the store c: { } ``` -------------------------------- ### Install @zedux/machines and @zedux/atoms packages Source: https://zedux.dev/packages/machines/overview Instructions for installing the `@zedux/machines` package, which has a peer dependency on `@zedux/atoms`. Commands are provided for npm, yarn, and pnpm. Separate commands are shown for general use and for React applications where `@zedux/react` is already present. ```yarn yarn add @zedux/atoms @zedux/machines ``` ```pnpm pnpm add @zedux/atoms @zedux/machines ``` ```npm npm install @zedux/react @zedux/machines ``` ```yarn yarn add @zedux/react @zedux/machines ``` ```pnpm pnpm add @zedux/react @zedux/machines ``` -------------------------------- ### Install @zedux/immer Package Source: https://zedux.dev/packages/immer Instructions for installing the @zedux/immer package and its peer dependencies (immer, @zedux/atoms, or @zedux/react) using npm, yarn, or pnpm. Ensure @zedux/atoms is at the same version as this package, or use @zedux/react if building a React application. ```bash npm install immer @zedux/atoms @zedux/immer yarn add immer @zedux/atoms @zedux/immer pnpm add immer @zedux/atoms @zedux/immer npm install immer @zedux/react @zedux/immer yarn add immer @zedux/react @zedux/immer pnpm add immer @zedux/react @zedux/immer ``` -------------------------------- ### guard Function Usage Example Source: https://zedux.dev/packages/machines/injectMachineStore Provides an example of implementing a `guard` function to prevent state transitions based on a condition, such as checking if the machine's context indicates it is paused. ```JavaScript const store = injectMachineStore(statesFactory, initialContext, { guard: (currentState, nextValue) => !currentState.context.isPaused }) ``` -------------------------------- ### Example Usage of Zedux Store and Action Type Helpers Source: https://zedux.dev/advanced/typescript-tips Provides a practical example demonstrating how to import and use various Zedux utility types (`StoreStateType`, `ActionFactoryTypeType`, etc.) to infer and verify types related to stores and actions in a TypeScript application. This showcases how to extract specific type information for enhanced type safety. ```typescript import { ActionFactoryTypeType, ActionFactoryPayloadType, ActionFactoryActionType, ActionTypeType, ActionPayloadType, ActionMetaType, actionFactory, createStore, StoreStateType, } from '@zedux/react' type Todo = { text: string } const store = createStore(null, 'Hello, world!') type State = StoreStateType // string const addTodo = actionFactory('addTodo') const action = addTodo({ text: 'Use TS' }) type Test = [ ActionFactoryTypeType, // 'addTodo' ActionFactoryPayloadType, // Todo ActionFactoryActionType, // { type: 'addTodo'; payload: Todo } ActionTypeType, // 'addTodo' ActionPayloadType, // Todo ActionMetaType // any ] ``` -------------------------------- ### Miscellaneous Usage Examples for injectCallback Source: https://zedux.dev/api/injectors/injectCallback Provides various examples of `injectCallback` usage, including basic function memoization, dependency arrays, and a comparison with `injectMemo` for scenarios where automatic batching is not desired. ```TypeScript import { injectCallback, injectMemo } from '@zedux/react' const add = injectCallback((a: number, b: number) => a + b, []) const withDeps = injectCallback(myFn, [depA, depB]) // to prevent automatic batching, use `injectMemo` instead ... const withoutBatching = injectMemo(() => myFn, [depA, depB]) // ... or use an inline function if memoization isn't needed: const inlineCallback = myFn ``` -------------------------------- ### Accessing Atom Instances in React Components Source: https://zedux.dev/walkthrough/quick-start Illustrates how to use `useAtomInstance()` in a React component to get a direct reference to an atom instance without subscribing to its state updates. This is useful for performing actions like `setState()` without triggering component re-renders, as shown in the `ToggleButton` example where the component updates state but doesn't need to re-render based on the value. ```javascript function MyComponent() { const instance = useAtomInstance(myAtomTemplate) ... } function ToggleButton() { // this component updates the togglerAtom instance's state, but doesn't need // the value during render thanks to `.setState()`'s function overload const instance = useAtomInstance(togglerAtom) return ( ) } ``` -------------------------------- ### Full Example: Using useAtomContext with AtomProvider Source: https://zedux.dev/api/hooks/useAtomContext A comprehensive example demonstrating the creation of an atom, its provision via ``, and consumption using `useAtomContext` and `useAtomValue` in child components. It showcases dynamic state updates and dependency management. ```typescript const secondsAtom = atom('seconds', () => { const store = injectStore(0) injectEffect(() => { const intervalId = setInterval(() => store.setState(val => val + 1), 1000) return () => clearInterval(intervalId) }, []) return store }) function Child() { const instance = useAtomContext(secondsAtom) const state = useAtomValue(instance) return
Child Seconds: {state}
} function Parent() { const instance = useAtomInstance(secondsAtom) return ( ) } ``` -------------------------------- ### Set Atom State with useAtomState Hook Source: https://zedux.dev/walkthrough/quick-start Demonstrates how to define an atom with an initial state and update its value using the `useAtomState` hook, similar to React's `useState`. The example shows an input field that modifies the atom's state, causing the component to re-render. ```JavaScript const greetingAtom = atom('greeting', 'Hello, world!') const Greeting = () => { const [greeting, setGreeting] = useAtomState(greetingAtom) return ( setGreeting(target.value)} value={greeting} /> ) } ``` -------------------------------- ### Instantiating ZeduxPlugin Source: https://zedux.dev/api/classes/ZeduxPlugin Shows the basic way to create a new instance of the `ZeduxPlugin` class using the `new` keyword. ```javascript const myPlugin = new ZeduxPlugin() ``` -------------------------------- ### Memoizing Atom Values with `injectMemo` Source: https://zedux.dev/walkthrough/quick-start Demonstrates how to use `injectMemo` within a Zedux atom factory to memoize a value, similar to React's `useMemo`, preventing re-evaluation of the atom when dependencies change. It shows how to get an initial price from a frequently changing stock price atom and memoize it for stable access. ```javascript import { atom, injectMemo } from '@zedux/react' const initialPriceAtom = atom('initialPrice', () => { // Let's say stockPriceAtom's state changes frequently: const [stockPrice] = injectAtomState(stockPriceAtom) // memoize the value on initial evaluation and never update it: const initialPrice = injectMemo(() => stockPrice, []) return initialPrice }) ``` -------------------------------- ### Creating Zedux Stores with createStore() Source: https://zedux.dev/api/classes/Store Demonstrates various ways to instantiate a Zedux store using the `createStore()` factory. Examples include creating a store with no arguments, with a root reducer, with initial state, with both, or by splitting reducers and composing child stores. ```javascript import { createStore } from '@zedux/react' const store = createStore() const withReducer = createStore(rootReducer) const withInitialState = createStore(null, initialState) const withBoth = createStore(rootReducer, initialState) const splittingReducers = createStore({ a: reducerA, b: reducerB, }) const childStores = createStore({ a: storeA, b: storeB, }) const mixed = createStore({ a: reducerA, b: storeB, }) ``` -------------------------------- ### Example: Using `injectAtomState` and Destructuring Exports Source: https://zedux.dev/api/injectors/injectAtomState This JavaScript example demonstrates the typical usage of `injectAtomState` to get the atom's state and setter, and specifically highlights how to destructure exports directly from the returned `setState` function. ```JavaScript const [state, setState] = injectAtomState(myAtom) const { export1, export2 } = setState // or simply: const [state, { export1, export2 }] = injectAtomState(myAtom) ``` -------------------------------- ### Examples of `api` factory usage and configuration Source: https://zedux.dev/api/factories/api Illustrates various ways to instantiate and configure `api` instances. This includes initializing with values, injecting stores, setting exports, handling promises, cloning existing APIs, adding/overwriting exports, and defining time-to-live (TTL) for API instances. ```javascript const myApi = api() const withValue = api('some value') const withStore = api(injectStore()) const withExports = api(val).setExports({ ...myExports }) const withPromise = api(val).setPromise(myPromise) const cloningApis = api(myApi).addExports(withExports.exports) const addingExports = api(withExports).addExports({ ...moreExports }) const overwritingExports = api(withExports).setExports({ ...newExports }) const settingTtl = api().setTtl(0) const ttlPromise = api().setTtl(myPromise) const ttlObservable = api().setTtl(my$) // query atoms: return api(myPromise) ``` -------------------------------- ### Example Usage of SelectorCache with Atom Selectors Source: https://zedux.dev/api/classes/SelectorCache This JavaScript example demonstrates how to create an ecosystem, define an atom and an atom selector, and then retrieve a `SelectorCache` item using `ecosystem.selectors.getCache()`. It illustrates the basic setup for working with cached selectors in Zedux. ```javascript const ecosystem = createEcosystem({ id: 'selector-cache-item-example' }) const numbersAtom = atom('numbers', () => [1, 2, 3, 4, 5, 6, 7]) const getOddNumbers = ({ get }: AtomGetters) => get(numbersAtom).filter(num => num % 2) const cacheItem = ecosystem.selectors.getCache(getOddNumbers) ``` -------------------------------- ### Examples of createStore Function Usage Source: https://zedux.dev/api/factories/createStore Illustrates various ways to use the `createStore` function, including creating zero-config stores, stores with initial state, reducer-based stores, machine stores, and complex composed stores by combining multiple stores or reducers. ```javascript import { createStore } from '@zedux/react' const zeroConfigStore = createStore() zeroConfigStore.setState('initial state') const zeroConfigStoreWithInitialState = createStore(null, 'initial state') zeroConfigStoreWithInitialState.setState('new state') const reducerStore = createStore(myRootReducer) reducerStore.dispatch({ type: 'my-action-type' }) const machineStore = createStore(stateMachine) machineStore.dispatch({ type: 'my-action-type' }) const composedStore = createStore({ zeroConfig: zeroConfigStore, reducerStore: reducerStore, machineStore: machineStore, }) const bigComposedStore = createStore({ a: storeA, b: reducerB, c: { d: reducerD, e: storeE, f: { g: storeG, }, }, }) ``` -------------------------------- ### Example: Lazy Atom with Ecosystem Get and Force Update Source: https://zedux.dev/api/injectors/injectAtomGetters Illustrates using `injectAtomGetters` with `ecosystem.get` to access atom values, highlighting the difference from a direct `get` call. It also shows how to create a 'lazy' atom using `ion` and invalidate an atom instance. ```typescript const secondsAtom = atom('seconds', () => { const store = injectStore(0) injectEffect(() => { const intervalId = setInterval(() => store.setState(val => val + 1), 1000) return () => clearInterval(intervalId) }, []) return store }) const lazyAtom = ion('lazy', ({ get }) => { const { ecosystem } = injectAtomGetters() // ion's get function would register a dynamic graph dependency here. // Try removing the "ecosystem.": const seconds = ecosystem.get(secondsAtom) return seconds }) function Seconds() { const lazySeconds = useAtomValue(lazyAtom) const instance = useAtomInstance(lazyAtom) return ( <>
Unchanging Seconds: {lazySeconds}
) } ``` -------------------------------- ### Creating AtomApi Instances Source: https://zedux.dev/api/classes/AtomApi Demonstrates various ways to create AtomApi instances using the `api()` factory, including initializing with values, stores, exports, and promises, and composing existing APIs. ```javascript import { api } from '@zedux/react' const myApi = api() const withValue = api('some value') const withStore = api(createStore()) const withExports = api(val).setExports({ ...myExports }) const withPromise = api(val).setPromise(myPromise) const fromApi = api(myApi) const addingExports = api(withExports).addExports({ ...moreExports }) const overwritingExports = api(withExports).setExports({ ...newExports }) ``` -------------------------------- ### Basic Usage of injectMachineStore Source: https://zedux.dev/packages/machines/injectMachineStore Demonstrates the fundamental way to create a `MachineStore` using `injectMachineStore`. It accepts a `stateFactory` function to define states and transitions, an optional `initialContext` object for the machine's context, and an optional configuration object for `guard` and `onTransition` callbacks. ```typescript const cyclingStore = injectMachineStore(stateFactory, initialContext, { guard, onTransition, }) ``` -------------------------------- ### Miscellaneous Usage of AtomGetters Methods Source: https://zedux.dev/api/injectors/injectAtomGetters Provides various examples of how to use the different methods available on the `AtomGetters` object, including `ecosystem`, `get`, `getInstance`, and `select`. It covers dynamic vs. static dependencies, parameter passing, usage in loops, control flow, asynchronously, and getting values from an atom instance. ```typescript const { ecosystem, get, getInstance, select } = injectAtomGetters() const dynamicVal = get(myAtom) const staticVal = ecosystem.get(myAtom) const instance = getInstance(myAtom) const selectedVal = select(myAtomSelector) const withParams = get(myAtom, ['param 1', 'param 2']) const instanceWithParams = getInstance(myAtom, ['param 1', 'param 2']) // AtomGetters can be used in loops: for (const id of ids) { const val = get(myAtom, [id]) } // .. any kind of loop ids.map(id => get(myAtom, [id])) // in control flow statements const val = useAtomA ? get(atomA) : get(atomB) // asynchronously: injectEffect(() => { const currentVal = get(myAtom) }, []) // don't have to pass `get` // passing an instance to get (also registers a dynamic dependency when called // during atom evaluation): const fromInstance = get(instance) ``` -------------------------------- ### Comprehensive Example of Conditional Atom Getters and Injectors Source: https://zedux.dev/walkthrough/atom-getters This extensive example demonstrates the interplay of `atom`, `injectStore`, `injectAtomGetters`, and React hooks like `useAtomInstance`, `useAtomState`, and `useAtomValue` within a counter application. It highlights that Atom Getters (like `get` and `getInstance`) can be used conditionally within loops, unlike traditional injectors/hooks. ```JavaScript // Let's do a bigger example. This is a good opportunity to review what // we've covered in the walkthrough so far! const counterAtom = atom('counter', (id: number) => 0) const counterIdsAtom = atom('counterIds', () => { const store = injectStore([0, 1]) const addCounter = () => store.setState(state => [...state, state.length]) return api(store).setExports({ addCounter }) }) const countersSumAtom = atom('countersSum', () => { const { get, getInstance } = injectAtomGetters() const counterIds = get(counterIdsAtom) let sum = 0 for (let counterId of counterIds) { sum += get(counterAtom, [counterId]) // loops are fine! } return sum }) function Counter({ id }: { id: number }) { const counterInstance = useAtomInstance(counterAtom, [id]) const [state, setState] = useAtomState(counterInstance) // dynamicize the dep! return (
Counter #{counterInstance.params[0]}: {state}{' '}
) } function CounterList() { const sum = useAtomValue(countersSumAtom) const counterIdsInstance = useAtomInstance(counterIdsAtom) const [ids, setIds] = useAtomState(counterIdsInstance) // dynamicize the dep! const { addCounter } = counterIdsInstance.exports return ( <> {ids.map(id => ( ))}
Sum: {sum}
) } ``` -------------------------------- ### Example ZeduxPlugin Usage with State Changed Mod Source: https://zedux.dev/api/classes/ZeduxPlugin Illustrates how to create a `ZeduxPlugin` instance, initialize it with specific mods, and register it with an ecosystem. It shows how to subscribe to the ecosystem's `modBus` to handle specific mod events, such as `stateChanged`. ```javascript const plugin = new ZeduxPlugin({ initialMods: ['stateChanged'], registerEcosystem: ecosystem => { const subscription = ecosystem.modBus.subscribe({ effects: ({ action }) => { if (action.type === ZeduxPlugin.actions.stateChanged.type) { // handle stateChanged mod event } }, }) return () => subscription.unsubscribe() }, }) const ecosystem = createEcosystem({ id: 'root' }) ecosystem.registerPlugin(plugin) ``` -------------------------------- ### Create a Basic Signal Source: https://zedux.dev/migrations/v2 This snippet shows how to create a simple signal using `ecosystem.signal` to manage state outside of atoms, demonstrating the fundamental way to instantiate a signal. ```JavaScript const signal = ecosystem.signal('some state') ``` -------------------------------- ### injectMachineStore API Reference Source: https://zedux.dev/packages/machines/injectMachineStore Comprehensive API documentation for the `injectMachineStore` function, detailing its parameters (`statesFactory`, `initialContext`, `config`) and their sub-properties, along with the function's return value and overall behavior. ```APIDOC injectMachineStore(statesFactory, initialContext?, config?) -> MachineStore Parameters: statesFactory: (Required) A function that returns an array of "states". Signature: (createState: (stateName: Name) => MachineState) => [...States] Description: States are created using the received `createState` factory function. Returns: An array of MachineStates created using the `createState` factory function. The first state in this list will become the initial state of the machine. initialContext?: (Optional) An object or `undefined`. Description: If set, this will become the initial value of the MachineStore's `.context` state property. config?: (Optional) An object with the following optional properties: guard?: (Optional) A function that receives the MachineStore's current state and the `.value` string the machine is about to transition to. Signature: (currentState: MachineStateShape, nextValue: StateNames) => boolean Description: Called every time the state receives an event that will transition the machine to a new state. Return `true` to allow the transition, `false` (or any falsy value) to prevent the transition. onTransition?: (Optional) A function that receives the MachineStore and the StoreEffect of the action responsible for the transition. Signature: MachineHook (simplified: (currentState, nextState) => void) Description: Called every time the MachineStore transitions to a new state (after the transition has finished). Returns: MachineStore: A MachineStore instance. - This store's initial `.value` will be set to the first state returned from the `statesFactory`. - This store's initial `.context` will be set to the passed `initialContext` (if any). - `injectMachineStore()` will also register all guards and listeners on all individual states as well as the universal guard and `onTransition` listener. ``` -------------------------------- ### Example: Summing Multiple Atom Counters with injectAtomGetters Source: https://zedux.dev/api/injectors/injectAtomGetters Demonstrates how to use `injectAtomGetters` within an atom to sum values from other atoms. It shows `injectStore` for state management, `injectEffect` for side effects, and `get` from `injectAtomGetters` to retrieve values from other atoms dynamically within a loop. ```typescript const secondsAtom = atom('seconds', (startingNumber: number) => { const store = injectStore(startingNumber) injectEffect(() => { const intervalId = setInterval(() => store.setState(val => val + 1), 1000) return () => clearInterval(intervalId) }, []) return store }) const sumAtom = atom('sum', (...nums: number[]) => { const { get } = injectAtomGetters() // loops are fine! return nums.reduce((sum, num) => sum + get(secondsAtom, [num]), 0) }) function Seconds() { const sum = useAtomValue(sumAtom, [1, 10, 100]) return
Sum of 3 counters: {sum}
} ``` -------------------------------- ### Zedux Atom Hydration Behavior Source: https://zedux.dev/migrations/v2 An example demonstrating how Zedux automatically hydrates atoms immediately after initial evaluation, making explicit hydration logic often unnecessary for derived signals. It highlights that hydrating at the source prevents double-evaluation. ```JavaScript // this atom behaves the same with or without these commented lines: const hydratingAtom = atom('hydrating', () => { const signalA = injectSignal('state a') const signalB = injectSignal('state b') // const hydration = injectHydration() const composedSignal = injectMappedSignal({ a: signalA, b: signalB }) // composedSignal.set(hydration) return composedSignal }) ``` -------------------------------- ### Zedux Zero-Config Store Example Source: https://zedux.dev/about/redux-comparison Reiterates the simplicity of creating a Zedux store without any explicit configuration or reducer, emphasizing its common usage. ```JavaScript const zeroConfigStore = createStore() ``` -------------------------------- ### Accessing Atom Instance Store and Basic Operations Source: https://zedux.dev/walkthrough/atom-instances Shows how an atom can return a store and how to access that store via the `instance.store` property of the `AtomInstance`. It also includes a quick recap of basic store operations like `getState()`, `setState()`, and `setStateDeep()` for managing the store's state. ```TypeScript const storeAtom = atom('store', () => { const store = injectStore('initial state') return store }) function MyComponent() { const instance = useAtomInstance(storeAtom) instance.store // <- this is the exact same store that we returned } store.getState() // returns the current state of the store store.setState('new state') // overwrites the store's state // recursively merge state into existing state: store.setStateDeep({ deeply: { merge: 'this state' } }) // function overloads - set new state based on current state store.setState(state => state + 1) store.setStateDeep(state => ({ someKey: state.someKey + 1 })) ``` -------------------------------- ### Initialize Zedux Stores and Subscribe to Parent Store Source: https://zedux.dev/advanced/time-travel This snippet demonstrates the initial setup of multiple Zedux stores (`formStore`, `emailStore`, `passwordStore`) and how to combine them using `formStore.use`. It also shows how to attach a basic subscriber to the `formStore` to react to state changes, laying the groundwork for history tracking. ```JavaScript const formStore = createStore() const emailStore = createStore(null, '') const passwordStore = createStore(null, '') formStore.use({ email: emailStore, password: passwordStore, }) formStore.subscribe((newState, oldState) => { if (newState === oldState) return // we'll add this logic next }) ``` -------------------------------- ### Optimizing Atom Graph Dependencies with Zedux Getters Source: https://zedux.dev/walkthrough/atom-getters This example illustrates Zedux's efficiency in handling graph updates. It shows that subsequent calls to `get` or `getInstance` for an atom that already has a registered dynamic dependency will not create redundant graph edges, preventing unnecessary updates. ```JavaScript const exampleAtom = atom('example', () => { const { get, getInstance } = injectAtomGetters() // registers a dynamic graph dependency on myAtom: const someField = get(myAtom).someField // doesn't register anything! (We've already registered this dep): const anotherField = get(myAtom).anotherField // also registers nothing (can't downgrade an edge from dynamic to static): const instance = getInstance(myAtom) }) ``` -------------------------------- ### Prefetch Specific Atoms Before Zedux SSR Source: https://zedux.dev/advanced/ssr This example illustrates how to prefetch specific Zedux atoms before the initial server render. By explicitly getting atom instances and awaiting their promises, you can ensure that necessary data is fetched and available in the ecosystem's state before the application components are rendered and the state is dehydrated. ```JavaScript async function renderRoute(req, res) { const ecosystem = createEcosystem({ id: 'root', ssr: true, }) await prefetchAtoms(ecosystem) const output = renderApp(ecosystem) const snapshot = ecosystem.dehydrate({ excludeFlags: ['unserializable'] }) ecosystem.destroy(true) res.send(`
${output}