### Install and Run Concurrent Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/examples/v7-concurrent/README.md Install dependencies and start the development server for the concurrent React example. ```sh yarn install yarn dev ``` -------------------------------- ### Install Dependencies Source: https://github.com/ctrlplusb/easy-peasy/blob/master/examples/react-native-todo/README.md Run this command to install all necessary project dependencies. ```bash yarn ``` -------------------------------- ### Install Easy Peasy Source: https://github.com/ctrlplusb/easy-peasy/blob/master/README.md Install the beta version of Easy Peasy using npm. ```bash npm install easy-peasy@beta ``` -------------------------------- ### Start Metro Bundler Source: https://github.com/ctrlplusb/easy-peasy/blob/master/examples/react-native-todo/README.md If the Metro bundler does not start automatically, use this command to manually start it. ```bash npx react-native start ``` -------------------------------- ### Install React Redux Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/recipes/usage-with-react-redux.md Install the `react-redux` package to enable integration with Easy Peasy. ```bash npm install react-redux ``` -------------------------------- ### Install Dependencies with Yarn Source: https://github.com/ctrlplusb/easy-peasy/blob/master/CLAUDE.md Use this command to install all project dependencies. ```bash yarn install ``` -------------------------------- ### Install React Dependencies Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/introduction/installation.md Ensure React and React DOM are installed before proceeding with Easy Peasy installation. These are prerequisites for Easy Peasy v7. ```bash npm install react npm install react-dom ``` -------------------------------- ### Run Development Server Source: https://github.com/ctrlplusb/easy-peasy/blob/master/examples/simple-todo/README.md Use this command to start the development server for the project. Open http://localhost:3000 in your browser to view the application. ```bash yarn dev ``` -------------------------------- ### Computed Example with Store State Resolvers Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/computed.md An example illustrating how to use computed properties with state resolvers that access the entire store state. ```APIDOC ## Computed Example with Store State Resolvers ### Description This example demonstrates using `computed` with multiple state resolvers, including one that accesses the global store state (`storeState`). ### Code ```typescript import { Computed, computed } from 'easy-peasy'; import { StoreModel } from './index'; // Assuming StoreModel is defined elsewhere interface BasketModel { productIds: string[]; products: Computed; } const basketModel: BasketModel = { productIds: [], products: computed( [ state => state.productIds, (state, storeState) => storeState.products.items ], (productIds, products) => productIds.map(id => products[id]) ) } ``` ``` -------------------------------- ### Basic useLocalStore Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-local-store.md Demonstrates the fundamental usage of useLocalStore to manage a simple counter state within a React component. ```javascript function MyCounter() { const [state, actions] = useLocalStore(() => ({ count: 0, increment: action((_state) => { _state.count += 1; }), })); return (
{state.count}
); } ``` -------------------------------- ### Create a Context Store Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/create-context-store.md Define a new context store with initial state and actions. This example shows a simple counter store. ```javascript import { createContextStore } from 'easy-peasy'; const CounterStore = createContextStore({ count: 0, increment: action((state) => { state.count += 1; }), }); export default CounterStore; ``` -------------------------------- ### Action Usage Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/action.md An example demonstrating how to define and use an Action within a model, including type definitions for the model and the action's payload. ```APIDOC ## Example Usage ### Description An example demonstrating how to define and use an Action within a model, including type definitions for the model and the action's payload. ### Code ```typescript import { Action, action } from 'easy-peasy'; interface TodosModel { todos: string[]; addTodo: Action; } const todosModel: TodosModel = { todos: [], addTodo: action((state, payload) => { state.todos.push(payload); }) } ``` ``` -------------------------------- ### Initial Store Implementation with Repeated Patterns Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/recipes/generalising-models.md This example shows a typical store structure with duplicated logic for products and users. It highlights the pattern that can be abstracted into a helper function. ```javascript const store = createStore({ products: { data: {}, ids: computed( [state => state.data], (resolvedState) => { const [data] = resolvedState; return Object.keys(state.data) } ), fetched: action((state, products) => { products.forEach(product => { state.data[product.id] = product; }); }), fetch: thunk(async (actions) => { const data = await fetchProducts(); actions.fetched(data); }) }, users: { data: {}, ids: computed( [state => state.data], (resolvedState) => { const [data] = resolvedState; return Object.keys(state.data) } ), fetched: action((state, users) => { users.forEach(user => { state.data[user.id] = user; }); }), fetch: thunk(async (dispatch) => { const data = await fetchUsers(); actions.fetched(data); }) } }) ``` -------------------------------- ### Basic useStoreTransition Usage Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-transition.md This snippet shows the basic setup for useStoreTransition, wrapping a single action dispatch. ```javascript const [addTodo, isPending] = useStoreTransition( (actions) => actions.todos.add, ); ``` -------------------------------- ### Access State with useStore - React Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store.md Import and use the useStore hook in a React component to access the store's state. This example shows how to retrieve and display the 'sayHello' state. ```javascript import { useStore } from 'easy-peasy'; const AddTodo = () => { const store = useStore(); return (
{store.getState().sayHello}
); }; ``` -------------------------------- ### Reducer Usage Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/reducer.md This example demonstrates how to define a store model with a 'todos' reducer, managing an array of strings. It shows the basic structure of a reducer function that handles 'ADD_TODO' actions. ```APIDOC ## Example Usage ### Description Illustrates how to integrate a reducer into your Easy-peasy store model to manage a list of todos. ### Code ```typescript import { Reducer, reducer } from 'easy-peasy'; interface StoreModel { todos: Reducer; } const storeModel: StoreModel = { todos: reducer((state = [], action) => { switch (action.type) { case 'ADD_TODO': return [...state, action.payload]; default: return state; } }) } ``` ``` -------------------------------- ### Basic Computed Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/computed.md An example demonstrating how to define a simple computed property that derives a number from a list of strings in the model. ```APIDOC ## Basic Computed Example ### Description This example shows a basic usage of `computed` to derive the length of the `todos` array. ### Code ```typescript import { Computed, computed } from 'easy-peasy'; interface TodosModel { todos: string[]; count: Computed; } const todosModel: TodosModel = { todos: [], count: computed(state => state.todos.length) } ``` ``` -------------------------------- ### ThunkOn Usage Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/thunk-on.md An example demonstrating how to use the `thunkOn` function to create a listener that reacts to the `addTodo` action and performs side effects like auditing and logging. ```APIDOC ## Example Usage of thunkOn ### Description This example shows how to define a `ThunkOn` listener named `onTodoAdded` within an `AuditModel`. This listener is triggered when the `addTodo` action (from another part of the store) is dispatched. Inside the listener, it uses injections to audit the action and then dispatches another action (`addLog`) to record the event. ### Code ```typescript import { ThunkOn, thunkOn, Action, action } from 'easy-peasy'; import { StoreModel, Injections } from '../index'; interface AuditModel { logs: string[]; addLog: Action; onTodoAdded: ThunkOn; } const auditModel: AuditModel = { logs: [], addLog: action((state, payload) => { state.logs.push(payload); }), onTodoAdded: thunkOn( (actions, storeActions) => storeActions.todos.addTodo, async (actions, payload, { injections }) => { await injections.auditService.add(`Added todo: ${payload}`); actions.addLog(`Added todo: ${payload}`); } ) } ``` ``` -------------------------------- ### Full Example with Store Integration Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/reducer.md Demonstrates how to use the reducer API within a store configuration and how to interact with the state and dispatch actions in a React component. It includes necessary imports for Easy Peasy. ```javascript import { createStore, reducer, useStoreState, useStoreDispatch, } from 'easy-peasy'; const store = createStore({ counter: reducer((state = 1, action) => { switch (action.type) { case 'INCREMENT': return state + 1; default: return state; } }), }); function Counter() { const count = useStoreState((state) => state.counter); const dispatch = useStoreDispatch(); return ( ); } ``` -------------------------------- ### Thunk Declaration and Usage Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/thunk.md An example demonstrating how to declare a thunk within a model, including its payload, injections, and how to dispatch it. ```APIDOC ## Thunk Declaration and Usage Example ```typescript import { Thunk, thunk, action, Action } from 'easy-peasy'; import { Injections } from './my-store.types.ts'; interface TodosModel { todos: string[]; savedTodo: Action; saveTodo: Thunk; } const todosModel: TodosModel = { todos: [], savedTodo: action((state, payload) => { state.todos.push(payload); }), saveTodo: thunk(async (actions, payload, { injections }) => { await injections.todosService.save(payload); actions.savedTodo(payload); }), }; // Dispatching the thunk: const doSaveTodo = useStoreActions((actions) => actions.saveTodo); await doSaveTodo('New Todo Item'); ``` ### Description This example shows a `saveTodo` thunk that takes a string payload, uses injections for a service call, and then dispatches a regular action `savedTodo` to update the state. It also demonstrates how to dispatch this thunk using `useStoreActions`. ``` -------------------------------- ### Add Upstream Remote and Fetch Source: https://github.com/ctrlplusb/easy-peasy/blob/master/CONTRIBUTING.md Add the original repository as a remote named 'upstream' and fetch its git information. This is a one-time setup step. ```bash git remote add upstream https://github.com/ctrlplusb/easy-peasy.git git fetch upstream git branch --set-upstream-to=upstream/master master ``` -------------------------------- ### useLocalStore for Component-Level State Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-local-store.md A concise example of using useLocalStore to manage component state, including defining actions for state manipulation. Ensure 'easy-peasy' is imported. ```javascript import { useLocalStore } from 'easy-peasy'; function MyCounter() { const [state, actions] = useLocalStore(() => ({ count: 0, inc: action((_state) => { _state.count += 1; }), })); return ( <>
{state.count}
); } ``` -------------------------------- ### Dispatching and Using Returned Value from Thunk Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/primary-api.md Shows how to dispatch a thunk and log its returned value. This example demonstrates consuming the result of a synchronous thunk. ```javascript const thunkOne = useStoreActions((actions) => actions.thunkOne); const thunkDispatchResult = thunkOne('world'); console.log(thunkDispatchResult); // "hello world" ``` -------------------------------- ### Basic Action Declaration Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/action.md An example of declaring a simple action to add a todo item to the state. ```APIDOC ## Basic Action Declaration ### Description Declares an action that adds a payload to the items array in the state. ### Handler Signature action((state, payload) => { ... }) ### Parameters #### Handler Arguments - **state** (Object) - The current state object. Can be mutated directly. - **payload** (any) - The data passed when dispatching the action. ### Request Example ```javascript addTodo: action((state, payload) => { state.items.push(payload); }); ``` ``` -------------------------------- ### Persist with Migrations Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/persist.md Demonstrates how to configure the persist helper with migration functions to transform store state across different versions. A migrationVersion is required to specify the target version. ```typescript persist( {...}, { migrations: { migrationVersion: 2, 1: (state) => { ... }, 2: (state) => { ... }, }, } ); ``` -------------------------------- ### Get Store Instance - useStore Hook Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store.md Instantiate the store object by calling the useStore hook. This should only be used for advanced or exceptional cases. ```javascript const store = useStore(); ``` -------------------------------- ### Overwrite Strategy Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/persist.md Demonstrates the overwrite merge strategy, where persisted state completely replaces the store model's initial state. This is a risky strategy and should be used with caution. ```javascript import { persist, createStore } from 'easy-peasy'; const store = createStore( persist( { fruit: 'pear', }, { mergeStrategy: 'overwrite' }, ), ); ``` ```json { "city": "cape town" } ``` -------------------------------- ### Define Model with Listener and Action Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/testing.md Define a model including an action ('addTodo') and a listener ('onTodoAdded') that reacts to the action. This setup is for testing listener execution. ```javascript import { action, actionOn } from 'easy-peasy'; const model = { todos: [], logs: [], addTodo: action((state, payload) => { state.todos.push(payload); }), onTodoAdded: actionOn( (actions) => actions.addTodo, (state, target) => { state.logs.push(`Added todo: ${target.payload}`); }, ), }; ``` -------------------------------- ### Mapping Multiple Values with shallowequal Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-state.md This example demonstrates using the 'shallowequal' package with useStoreState to map multiple values while performing a shallow equality check on the returned object, optimizing re-renders. ```javascript import { useStoreState } from 'easy-peasy'; import shallowEqual from 'shallowequal'; function MyComponent() { const { item1, item2 } = useStoreState( state => ({ item1: state.items.item1, item2: state.items.item2, }), shallowEqual // 👈 we can just pass the reference as the function signature // is compatible with what the "equalityFn" argument expects ) } ``` -------------------------------- ### Refactored Store Using Data Model Helper Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/recipes/generalising-models.md This example demonstrates how to refactor the store definition to use the generic `dataModel` helper, reducing code duplication and improving readability. ```javascript const store = createStore({ products: { ...dataModel(fetchProducts) // attach other state/actions/etc as you like }, users: { ...dataModel(fetchUsers) } }) ``` -------------------------------- ### Fixed: Separate useStoreState Calls Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-state.md This example shows the recommended way to map multiple state values by using separate useStoreState hook calls for each value, ensuring optimized re-renders. ```javascript function Fixed() { const thing1 = useStoreState(state => state.thing1); const thing2 = useStoreState(state => state.thing2); return
I am optimised
; } ``` -------------------------------- ### Store Definition for Merge Strategy Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/persist.md This JavaScript code defines the initial store model used to demonstrate the 'mergeDeep' strategy. It includes various data types and nested objects. ```javascript import { persist, createStore } from 'easy-peasy'; const store = createStore( persist({ animal: 'dolphin', address: { city: 'london', postCode: 'e3 1pq', }, fruits: ['apple'], id: 1, name: null, counter: 20, }), ); ``` -------------------------------- ### Selector Optimization Example (Avoid) Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/primary-api.md Demonstrates selectors that may cause performance issues by returning new object or array instances on every state change, leading to unnecessary re-renders. ```javascript useStoreState((state) => { // We are creating a new object every time! return { name: state.name, age: state.age, }; }); useStoreState((state) => { // We are returning a new array every time! return [...state.fruits, ...state.vegetables]; }); ``` -------------------------------- ### Using useStoreState in a React Component Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-state.md Import and use useStoreState to access multiple pieces of state within a functional component. This example shows how to get both total and net prices from the basket state. ```javascript import { useStoreState } from 'easy-peasy'; const BasketTotal = () => { const totalPrice = useStoreState(state => state.basket.totalPrice); const netPrice = useStoreState(state => state.basket.netPrice); return (
Total: {totalPrice}
Net: {netPrice}
); }; ``` -------------------------------- ### Implementing Generic State with Easy Peasy Helpers Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/generic.md This example demonstrates the correct way to define and use generic state in an Easy Peasy store model using the `Generic` type for state definition and the `generic` helper for initial value assignment. It also shows how to use the state and actions within a component. ```typescript import { Generic, generic } from 'easy-peasy'; interface StoreModel { data: Generic; // 👈 define a generic state updateData: Action, K>; } const numberStoreModel: StoreModel = { data: generic(1337), // 👈 assign the initial value using the helper updateData: action((state, payload) => { // Note that you don't need to wrap the payload with the // helper 👇 state.data = payload; }) } function MyComponent() { const data = useStoreState(state => state.data); const updateData = useStoreActions(actions => actions.updateData); console.log(data) // 1337 console.log(typeof numberStoreModel.getState().data) // number updateData(7331); // 👈 no need to wrap payload with the helper } ``` -------------------------------- ### Basic effectOn Usage Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/effect-on.md This example demonstrates how to use effectOn to track changes in 'state.items'. When 'items' changes, it sets 'saving' to true, saves the items asynchronously, and then sets 'saving' back to false. ```javascript import { effectOn } from 'easy-peasy'; const todosModel = { items: [], saving: false, setSaving: action((state, payload) => { state.saving = payload; }), effectOn( // Provide an array of "stateResolvers" to resolve the targeted state: [state => state.items], // Provide a handler which will execute every time the targeted state changes: async (actions, change) => { const [items] = change.current; actions.setSaving(true); await todosService.save(items); actions.setSaving(false); } ) }; ``` -------------------------------- ### Fixed: Using useMemo for Derived State Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-state.md This example demonstrates how to use React's useMemo hook to optimize derived state calculations, ensuring the mapping logic only runs when the relevant state (products) changes. ```javascript import { useMemo } from 'react'; function FixedOptionOne() { const products = useStoreState(state => state.products.items); const productNames = useMemo( // We move our state deriving out of the useStoreState hook // 👇 () => products.map(product => product.name), [products] // 👈 tell React to rerun useMemo when products change ); return (
    {productNames.map(name =>
  • {name}
  • )}
); } ``` -------------------------------- ### Defining an ActionOn Listener Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/action-on.md This example demonstrates how to define an `actionOn` listener. It listens for the `addTodo` action from the `todos` part of the store and pushes a log message to the `logs` array in the `auditModel` when the action is dispatched. Ensure your `StoreModel` is correctly typed if targeting actions from other parts of the store. ```typescript import { ActionOn, actionOn } from 'easy-peasy'; import { StoreModel } from '../index'; interface AuditModel { logs: string[]; onTodoAdded: ActionOn; } const auditModel: AuditModel = { logs: [], onTodoAdded: actionOn( (actions, storeActions) => storeActions.todos.addTodo, (state, payload) => { state.logs.push(`Added todo: ${payload}`); } ) } ``` -------------------------------- ### Product Search with Deferred State Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-deferred-state.md This example shows how to use useStoreDeferredState for a product search feature. It filters a list of products based on user input, ensuring the input remains responsive even with large datasets by deferring the filtering process. ```javascript import { useState } from 'react'; import { useStoreDeferredState } from 'easy-peasy'; function ProductSearch() { const [query, setQuery] = useState(''); const matches = useStoreDeferredState((state) => state.products.items.filter((p) => p.name.includes(query)), ); return (
setQuery(e.target.value)} />
    {matches.map((p) =>
  • {p.name}
  • )}
); } ``` -------------------------------- ### Todo List with Optimistic Updates Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-optimistic.md This example showcases how to integrate useStoreOptimistic into a React component for managing a todo list. It uses startTransition to dispatch an asynchronous action while optimistically adding a new todo item with a 'pending' flag for visual feedback. The optimistic item is displayed with reduced opacity until the actual store update occurs. ```javascript import { startTransition } from 'react'; import { useStoreActions, useStoreOptimistic, } from 'easy-peasy'; function TodoList() { const [items, addOptimistic] = useStoreOptimistic( (state) => state.todos.items, (current, pending) => [...current, { ...pending, pending: true }], ); const addItemAsync = useStoreActions((a) => a.todos.addItemAsync); return (
    {items.map((item) => (
  • {item.text}
  • ))}
); } ``` -------------------------------- ### Configure Reactotron Instance Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/recipes/connecting-to-reactotron.md Set up a Reactotron instance with necessary plugins like reactotronRedux. This configuration is typically placed in a dedicated file. ```javascript // reactotron.js import Reactotron from 'reactotron-react-native'; import { reactotronRedux } from 'reactotron-redux'; const reactron = Reactotron.configure() .useReactNative() .use(reactotronRedux()) .connect(); export default reactron; ``` -------------------------------- ### Create a Store with Model and Configuration Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/create-store.md Demonstrates creating a store with a defined model including actions and a custom store name. This store is then integrated into a React application using StoreProvider. ```javascript import { createStore, StoreProvider, action } from 'easy-peasy'; const model = { todos: { items: [], addTodo: action((state, text) => { state.items.push(text); }), }, }; const store = createStore(model, { name: 'MyAwesomeStore', }); import { createRoot } from 'react-dom/client'; createRoot(document.querySelector('#app')).render( , ); ``` -------------------------------- ### Preview Production Build Source: https://github.com/ctrlplusb/easy-peasy/blob/master/examples/reduxtagram/README.md Serves the production build for previewing. ```shell yarn run preview ``` -------------------------------- ### Build Application Source: https://github.com/ctrlplusb/easy-peasy/blob/master/examples/reduxtagram/README.md Builds the application for production, outputting files to the `build` folder. ```shell yarn build ``` -------------------------------- ### Create Store Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/README.md Define your application's store with initial state and actions. ```javascript const store = createStore({ todos: ['Create store', 'Wrap application', 'Use store'], addTodo: action((state, payload) => { state.todos.push(payload); }), }); ``` -------------------------------- ### Create a Basic Easy Peasy Store Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/primary-api.md Use the `createStore` function with your model to initialize a store. This is the fundamental step for setting up Easy Peasy. ```javascript import { createStore } from 'easy-peasy'; import model from './model'; const store = createStore(model); ``` -------------------------------- ### Action with Immer Disabled Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/action.md An example of disabling Immer for an action, requiring manual state immutability management. ```APIDOC ## Action with Immer Disabled ### Description Demonstrates how to disable Immer for an action, which is useful for performance with large state structures. Requires manual immutable updates. ### Handler Signature action((state, payload) => { ... }, config) ### Parameters #### Handler Arguments - **state** (Object) - The current state object. - **payload** (any) - The data passed when dispatching the action. #### Config Object - **immer** (Boolean) - Set to `false` to disable Immer. Defaults to `true`. ### Request Example ```javascript import { action } from 'easy-peasy'; const model = { bigData: {/*...*/}, updateBigData: action( (state, payload) => { return { ...state, bigData: { ...state.bigData, ...payload, }, }; }, { immer: false, } ), }; ``` ``` -------------------------------- ### Create a Store with Initial State Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/primary-api.md Provide configuration options, such as `initialState`, to the `createStore` function. This is useful for server-side rendering or rehydration. ```javascript const store = createStore(model, { initialState: serverRenderedState, }); ``` -------------------------------- ### Run Tests in Watch Mode Source: https://github.com/ctrlplusb/easy-peasy/blob/master/CLAUDE.md Starts the Vitest test runner in watch mode, automatically re-running tests on file changes. ```bash yarn test:watch ``` -------------------------------- ### Create a Store Source: https://github.com/ctrlplusb/easy-peasy/blob/master/README.md Define your application's state and actions using createStore. ```javascript const store = createStore({ todos: ['Create store', 'Wrap application', 'Use store'], addTodo: action((state, payload) => { state.todos.push(payload); }), }); ``` -------------------------------- ### Returning Data from a Synchronous Thunk Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/primary-api.md Illustrates how a synchronous thunk can return a value, which is then available to the dispatcher. This example shows returning a string. ```javascript const model = { thunkOne: thunk((actions, payload) => { return `hello ${payload}`; }), }; ``` -------------------------------- ### Synchronous Thunk Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/primary-api.md Illustrates a synchronous thunk that dispatches one of two actions based on a condition. This shows that thunks do not have to be asynchronous. ```javascript const model = { actionOne: action((state, payload) => { /* ... */ }), actionTwo: action((state, payload) => { /* ... */ }), thunkOne: thunk((actions, payload) => { if (condition) { actions.actionOne(payload); } else { actions.actionTwo(payload); } }), }; ``` -------------------------------- ### Preload Store State for Testing Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/testing.md Utilize the `initialState` option when creating the store to preload it with specific state for testing particular conditions. ```javascript test('Counter', () => { // arrange const store = createStore(model, { initialState: initialStateForTest }); // ... }); ``` -------------------------------- ### Client Component with Server-Prepared Initial State Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/recipes/usage-with-rsc-and-next-app-router.md This client component initializes the Easy Peasy store with data (`initialItems`) received from a server component. This prevents a duplicate fetch and UI flash. ```javascript 'use client'; import { useRef } from 'react'; import { createStore, StoreProvider } from 'easy-peasy'; import { productsModel } from './store-model'; import { ProductsList } from './products-list'; export function ProductsClient({ initialItems }) { const storeRef = useRef(null); if (storeRef.current === null) { storeRef.current = createStore(productsModel, { initialState: { items: initialItems }, }); } return ( ); } ``` -------------------------------- ### Consume Store Dispatch with useStoreDispatch Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/create-context-store.md Use the useStoreDispatch hook to get access to the store's dispatch function for manual action dispatching. ```javascript function CountIncButton() { const dispatch = CounterStore.useStoreDispatch(); return ; } ``` -------------------------------- ### Create a Basic Store Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/create-store.md Initializes a simple store with a nested state structure. This is a fundamental step before providing the store to the application. ```javascript import { createStore } from 'easy-peasy'; const store = createStore({ todos: { items: [], }, }); ``` -------------------------------- ### Dispatch Thunks from Components Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/quick-start.md Access thunks in your components using the useStoreActions hook, similar to how you access regular actions. This example dispatches the saveTodo thunk. ```javascript import { useStoreActions } from 'easy-peasy'; function AddTodoForm() { const saveTodo = useStoreActions((actions) => actions.saveTodo); const [value, setValue] = React.useState(''); return ( <> setValue(e.target.value)} value={value} /> ); } ``` -------------------------------- ### Import from easy-peasy/server for React-Free Environments Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/upgrading-from-v6/README.md Provides a React-free entry point for using the store, helpers, and types in environments like React Server Components or edge runtimes where importing React is not suitable. ```javascript import { createStore, action } from 'easy-peasy/server'; ``` -------------------------------- ### Dispatching Actions in a Component Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-dispatch.md Use the dispatch function obtained from useStoreDispatch to send actions to your store. This example shows how to dispatch an 'ADD_TODO' action with a payload. ```javascript import { useState } from 'react'; import { useStoreDispatch } from 'easy-peasy'; const AddTodo = () => { const [text, setText] = useState(''); const dispatch = useStoreDispatch(); return (
setText(e.target.value)} />
); }; ``` -------------------------------- ### targetResolver Function Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/listeners.md The targetResolver function is the first argument to listener definitions. It receives actions and storeActions and should resolve the specific action(s) or thunk(s) to listen to. ```javascript onAddTodo: thunkOn( actions => actions.addTodo, // 👈 the targetResolver function async (actions, target) => { await auditService.add(`Added a todo: ${target.payload}`); } ) ``` -------------------------------- ### Basic Reducer Declaration Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/reducer.md A simple example of declaring a reducer for a state slice. The reducer function handles state updates based on action types. ```javascript reducer((state = 1, action) => { switch (action.type) { case 'INCREMENT': state + 1; default: return state; } }); ``` -------------------------------- ### Add a State Migration for Renaming a Property Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/persist.md Use migrations to handle cases where a property in your store model is renamed. This example shows how to migrate 'session' to 'userSession'. ```typescript persist( { userSession: true, }, { migrations: { migrationVersion: 1, // " 1: (state) => { state.userSession = state.session; // " delete state.session; // " }, }, }, ); ``` -------------------------------- ### Wrap application with both Redux and Easy Peasy providers Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/recipes/interop-with-existing-react-redux-app.md Demonstrates how to wrap your React application with both the `react-redux` Provider and Easy Peasy's `StoreProvider` to enable the use of hooks and connect from both libraries. ```javascript import { Provider } from 'react-redux'; import { StoreProvider } from 'easy-peasy'; import store from './store'; const app = ( ); ``` -------------------------------- ### Integrating StoreProvider in Root Layout Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/recipes/usage-with-rsc-and-next-app-router.md This server component demonstrates how to include the `StoreProvider` in your root layout to make the store available throughout the application. ```javascript import { StoreProvider } from './store-provider'; export default function RootLayout({ children }) { return ( {children} ); } ``` -------------------------------- ### Derive State with Computed Properties Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/quick-start.md Create derived state using the computed API. This example derives a list of completed todos from the main todos list. ```javascript import { computed } from 'easy-peasy'; const store = createStore({ todos: [{ text: 'Learn easy peasy', done: true }], completedTodos: computed((state) => state.todos.filter((todo) => todo.done)), }); ``` -------------------------------- ### useLocalStore with Store Configuration Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-local-store.md Shows how to provide custom store configuration, such as middleware, to useLocalStore. The store configuration function is called when dependencies change. ```javascript useLocalStore( () => model, [], () => ({ middleware: [loggerMiddleware] }), ); ``` -------------------------------- ### Fetching Products in a Server Component Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/recipes/usage-with-rsc-and-next-app-router.md This server component fetches product data using `fetchProducts` and passes it as a prop to the client component. ```javascript import { fetchProducts } from '@/lib/data'; import { ProductsClient } from './products-client'; export default async function ProductsPage() { const products = await fetchProducts(); return ; } ``` -------------------------------- ### Conventional Commit Example Source: https://github.com/ctrlplusb/easy-peasy/blob/master/CONTRIBUTING.md Follow the Conventional Commits specification for commit messages. Simple messages are acceptable for small changes, but detailed messages are preferred for clarity. ```git feat: add cool new feature ``` ```git feat: add cool new feature * detail about implementation of and/or motivation for the cool new feature * additional helpful details ``` -------------------------------- ### Persist Specific Nested Models Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/persist.md Target specific parts of your state by wrapping the desired nested models with `persist`. This allows for granular control over what gets persisted. ```javascript const store = createStore( products: productsModel, basket: persist(basketModel), session: persist(sessionModel) ); ``` -------------------------------- ### Get Store Dispatcher Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-dispatch.md Import and call the useStoreDispatch hook to obtain the store's dispatch function. This is the primary way to interact with your store's state. ```javascript const dispatch = useStoreDispatch(); ``` -------------------------------- ### Define a Basic Computed Property Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/primary-api.md Use the `computed` helper to define a derived state property based on existing state. This example shows how to derive the count of todos. ```javascript import { computed } from 'easy-peasy'; // upward const model = { todos: [], // downward todoCount: computed((state) => state.todos.length), }; ``` -------------------------------- ### Initialize Store with Versioning Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/persist.md Configure the store with a version number to enable forced updates of persisted state. This is useful after significant store model refactors. ```javascript const store = createStore( persist({ products: productsModel, basket: basketModel, session: sessionModel, }), { version: 1, " }, ); ``` -------------------------------- ### Define Entire Store Model Dynamically with createContextStore Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/create-context-store.md You can define the entire store model dynamically by returning the `runtimeModel` directly from the function passed to `createContextStore`. This allows the runtime model to dictate the store's structure and actions. ```javascript const Counter = createContextStore((runtimeModel) => runtimeModel); import { createRoot } from 'react-dom/client'; createRoot(document.querySelector('#app')).render( { state.count += 1; }), }} > , ); ``` -------------------------------- ### Use Store Deferred State Hook Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/create-context-store.md Use this hook to get a deferred selected state value. It's suitable for expensive selectors where stale-while-fresh behavior is acceptable. ```javascript function CountDisplay() { const count = CounterStore.useStoreDeferredState((state) => state.count); return
{count}
; } ``` -------------------------------- ### Creating Typed Hooks Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/typescript-api/create-typed-hooks.md Import `createTypedHooks` and your store model. Call `createTypedHooks` with your model to get typed hook versions. Export these typed hooks for use in components. ```typescript import { createTypedHooks } from 'easy-peasy'; import { StoreModel } from './model'; const { useStoreActions, useStoreState, useStoreDispatch, useStore, useStoreTransition, useStoreDeferredState, useStoreOptimistic, useStoreRehydrated, } = createTypedHooks(); export { useStoreActions, useStoreState, useStoreDispatch, useStore, useStoreTransition, useStoreDeferredState, useStoreOptimistic, useStoreRehydrated, }; ``` -------------------------------- ### Build Store in React Server Component Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/easy-peasy-server.md Demonstrates creating and populating a store within a React Server Component using the easy-peasy/server API. The store's initial state can then be passed to a client component for hydration. ```javascript import { createStore, persist, action } from 'easy-peasy/server'; import { ProductsView } from './products-view'; // 'use client' const productsModel = { items: [], setItems: action((state, payload) => { state.items = payload; }), }; export default async function ProductsPage() { const items = await fetch('https://example.com/api/products').then((r) => r.json(), ); const store = createStore(productsModel); store.getActions().setItems(items); // Pass the serialised initial state down to the client component, // which can hydrate its own client-side store with it. return ; } ``` -------------------------------- ### Accessing a Specific Action with useStoreActions Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/use-store-actions.md This snippet shows the basic usage of the useStoreActions hook to get a reference to a specific action, in this case, 'add' from the 'todos' slice of your store. ```javascript const addTodo = useStoreActions(actions => actions.todos.add); ``` -------------------------------- ### Run on iOS Source: https://github.com/ctrlplusb/easy-peasy/blob/master/examples/react-native-todo/README.md Execute this command to build and run the React Native application on an iOS simulator or device. ```bash yarn ios ``` -------------------------------- ### Customize Store Model at Runtime with createContextStore Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/api/create-context-store.md Use the `runtimeModel` prop on the Provider to customize your store's model when it's initialized. The function provided to `createContextStore` receives the runtime model data. ```javascript const Counter = createContextStore((runtimeModel) => ({ count: runtimeModel.count, inc: action((state) => { state.count += 1; }), })); import { createRoot } from 'react-dom/client'; createRoot(document.querySelector('#app')).render( , ); ``` -------------------------------- ### Create an Easy Peasy Store Source: https://github.com/ctrlplusb/easy-peasy/blob/master/website/docs/docs/tutorials/quick-start.md Define your application's state model using a plain JavaScript object and pass it to the createStore function. Your model can be as complex as needed. ```javascript import { createStore } from 'easy-peasy'; const store = createStore({ todos: [], }); ```