### Installing and Using React Devtools for Batshit Source: https://github.com/yornaath/batshit/blob/master/packages/batshit/README.md Provides instructions for installing the `@yornaath/batshit-devtools-react` package and demonstrates how to integrate the `BatshitDevtools` component into a React application for debugging batching processes. ```bash yarn add @yornaath/batshit-devtools @yornaath/batshit-devtools-react ``` ```typescript import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; import BatshitDevtools from "@yornaath/batshit-devtools-react"; const batcher = create({ fetcher: async (queries: number[]) => {...}, scheduler: windowScheduler(10), resolver: keyResolver("id"), name: "batcher:data" // used in the devtools to identify a particular batcher. }); const App = () => {
} ``` -------------------------------- ### Create a Batch Manager Instance Source: https://context7.com/yornaath/batshit/llms.txt Initializes a batch manager using a fetcher function, a resolver for mapping results, and a scheduler for timing. This setup allows multiple individual fetch calls to be combined into a single network request. ```typescript import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; type User = { id: number; name: string }; const users = create({ fetcher: async (ids: number[]) => { const response = await fetch(`/api/users?ids=${ids.join(",")}`); return response.json() as Promise; }, resolver: keyResolver("id"), scheduler: windowScheduler(10), name: "users-batcher", }); const [bob, alice, sally] = await Promise.all([ users.fetch(1), users.fetch(2), users.fetch(3), ]); ``` -------------------------------- ### Integrating Batshit React Devtools Source: https://github.com/yornaath/batshit/blob/master/README.md Provides instructions on how to install and integrate the Batshit React Devtools for debugging and inspecting batching processes within a React application. It shows how to add the `BatshitDevtools` component to the application. ```bash yarn add @yornaath/batshit-devtools @yornaath/batshit-devtools-react ``` -------------------------------- ### Configuring Batshit with Devtools Name Source: https://github.com/yornaath/batshit/blob/master/README.md Demonstrates the setup of a Batshit batcher and its integration with React Devtools. It highlights the use of the `name` option in `create` to identify specific batchers within the devtools interface. ```typescript import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; import BatshitDevtools from "@yornaath/batshit-devtools-react"; const batcher = create({ fetcher: async (queries: number[]) => {...}, scheduler: windowScheduler(10), resolver: keyResolver("id"), name: "batcher:data" // used in the devtools to identify a particular batcher. }); const App = () => {
} ``` -------------------------------- ### Install @yornaath/batshit Package Source: https://github.com/yornaath/batshit/blob/master/README.md This command installs the @yornaath/batshit package using Yarn, making its batching functionalities available for use in your project. ```bash yarn add @yornaath/batshit ``` -------------------------------- ### Initialize and use a basic Batcher Source: https://github.com/yornaath/batshit/blob/master/packages/devtools/README.md Demonstrates how to create a Batcher instance with a window scheduler and fetch multiple items simultaneously. The fetcher is triggered once for all requests made within the specified 10ms window. ```typescript import { Batcher, keyResolver, windowScheduler } from "@yornaath/batshit"; let fetchCalls = 0; type User = { id: number; name: string }; const users = Batcher({ fetcher: async (ids) => { fetchCalls++; return client.users.where({ userId_in: ids }); }, resolver: keyResolver("id"), scheduler: windowScheduler(10), }); const bob = users.fetch(1); const alice = users.fetch(2); const bobUndtAlice = await Promise.all([bob, alice]); ``` -------------------------------- ### Create a Simple Batcher with Window Scheduler Source: https://github.com/yornaath/batshit/blob/master/README.md Demonstrates creating a basic batcher using `@yornaath/batshit`. It configures a fetcher for user data, a key resolver based on user ID, and a `windowScheduler` that batches requests made within a 10ms window. Subsequent requests outside this window are batched separately. ```typescript import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; type User = { id: number; name: string }; const users = create({ fetcher: async (ids: number[]) => { return client.users.where({ id_in: ids, }); }, resolver: keyResolver("id"), scheduler: windowScheduler(10), // Default and can be omitted. }); /** * Requests will be batched to one call since they are done within the same time window of 10 ms. */ const bob = users.fetch(1); const alice = users.fetch(2); const bobUndtAlice = await Promise.all([bob, alice]); await delay(100); /** * New Requests will be batched in a another call since not within the first timeframe. */ const joe = users.fetch(3); const margareth = users.fetch(4); const joeUndtMargareth = await Promise.all([joe, margareth]); ``` -------------------------------- ### Indexed Keyresolver for Large Batches Source: https://github.com/yornaath/batshit/blob/master/README.md Details how to enable indexing for the `keyResolver` when dealing with very large batches (over 30K items). This optimization can significantly improve performance for such cases, though it offers negligible gains for smaller batches. ```typescript const batcherIndexed = create({ fetcher: async (ids: number[]) => { // returns > 30K items[] return mock.bigUserById(ids); }, resolver: keyResolver("id", { indexed: true }), scheduler: windowScheduler(1000), }); ``` -------------------------------- ### Custom Batch Resolver for User Posts Source: https://github.com/yornaath/batshit/blob/master/README.md Illustrates creating a custom batcher that fetches all posts for multiple users in a single request. The custom resolver then correctly filters and returns the posts for each individual user query, optimizing data retrieval. ```typescript const userposts = create({ fetcher: async (queries: { authorId: number }) => { return api.posts.where({ authorId_in: queries.map((q) => q.authorId), }); }, scheduler: windowScheduler(10), resolver: (posts, query) => posts.filter((post) => post.authorId === query.authorId), }); const [alicesPosts, bobsPost] = await Promise.all([ userposts.fetch({authorId: 1}) userposts.fetch({authorId: 2}) ]); ``` -------------------------------- ### Integrate Batshit with React Query Source: https://context7.com/yornaath/batshit/llms.txt Demonstrates how to use Batshit as a singleton instance alongside TanStack Query to batch multiple component-level requests into a single network call. This pattern significantly reduces redundant API traffic. ```typescript import { useQuery } from "@tanstack/react-query"; import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; type User = { id: number; name: string; email: string }; // Create batcher OUTSIDE of components (singleton pattern) const userBatcher = create({ fetcher: async (ids: number[]) => { const response = await fetch(`/api/users?ids=${ids.join(",")}`); return response.json() as Promise; }, resolver: keyResolver("id"), scheduler: windowScheduler(10), }); const useUser = (userId: number) => { return useQuery({ queryKey: ["user", userId], queryFn: () => userBatcher.fetch(userId), }); }; ``` -------------------------------- ### Batcher for Object Response with Indexed Resolver Source: https://github.com/yornaath/batshit/blob/master/README.md Demonstrates creating a batcher where the `fetcher` returns an object (record) of items, keyed by their IDs. It utilizes `batshit.indexedResolver()` to correctly map the fetched items back to their corresponding IDs, suitable for responses like `{"1": {"username": "bob"}, "2": {"username": "alice"}}`. ```typescript import * as batshit from "@yornaath/batshit"; const batcher = batshit.create({ fetcher: async (ids: string[]) => { const users: Record = await fetchUserRecords(ids) return users }, resolver: batshit.indexedResolver(), }); ``` -------------------------------- ### Implement a custom batch resolver Source: https://github.com/yornaath/batshit/blob/master/packages/devtools/README.md Illustrates creating a batcher that handles complex query objects rather than simple IDs. The custom resolver filters the fetched results to match the specific query criteria. ```typescript const userposts = create({ fetcher: async (queries) => { return api.posts.where({ authorId_in: queries.map((q) => q.authorId), }); }, scheduler: windowScheduler(10), resolver: (posts, query) => posts.filter((post) => post.authorId === query.authorId), }); const [alicesPosts, bobsPost] = await Promise.all([ userposts.fetch({authorId: 1}), userposts.fetch({authorId: 2}) ]); ``` -------------------------------- ### React Query Batcher with Window Scheduler Source: https://github.com/yornaath/batshit/blob/master/README.md Illustrates integrating `@yornaath/batshit` with `react-query` for efficient data fetching in React applications. It sets up a batcher for user data with a 10ms window scheduler. A custom hook `useUser` utilizes this batcher, ensuring that multiple `UserDetails` components rendered simultaneously result in a single batched API request. ```typescript import { useQuery } from "react-query"; import { create, windowScheduler } from "@yornaath/batshit"; const users = create({ fetcher: async (ids: number[]) => { return client.users.where({ userId_in: ids, }); }, resolver: keyResolver("id"), scheduler: windowScheduler(10), }); const useUser = (id: number) => { return useQuery(["users", id], async () => { return users.fetch(id); }); }; const UserDetails = (props: { userId: number }) => { const { isFetching, data } = useUser(props.userId); return ( <> {isFetching ? (
Loading user {props.userId}
) : (
User: {data.name}
)} ); }; /** * Since all user details items are rendered within the window there will only be one request made. */ const UserList = () => { const userIds = [1, 2, 3, 4]; return ( <> {userIds.map((id) => ( ))} ); }; ``` -------------------------------- ### Implement Memoized Batcher with Context Source: https://context7.com/yornaath/batshit/llms.txt Demonstrates how to use lodash memoize to create context-aware batcher instances. This ensures that batchers are reused based on specific SDK or client instances, preventing redundant initialization. ```typescript import { useQuery } from "@tanstack/react-query"; import { memoize } from "lodash-es"; import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; type Market = { marketId: number; name: string; volume: number }; type SDK = { markets: (params: { where: { marketId_in: number[] } }) => Promise<{ markets: Market[] }> }; const getMarketBatcher = memoize((sdk: SDK) => { return create({ fetcher: async (ids: number[]) => { const { markets } = await sdk.markets({ where: { marketId_in: ids }, }); return markets; }, resolver: keyResolver("marketId"), scheduler: windowScheduler(10), name: "markets-batcher", }); }); const useMarket = (marketId: number) => { const sdk = useSDK(); return useQuery({ queryKey: ["market", marketId], queryFn: () => getMarketBatcher(sdk).fetch(marketId), enabled: Boolean(sdk), }); }; ``` -------------------------------- ### Early Batch Execution with batcher.next() Source: https://github.com/yornaath/batshit/blob/master/README.md Shows how to trigger the execution of the current batch of requests before the scheduler's time limit is reached by calling `batcher.next()`. This is useful for scenarios where immediate processing is required. ```typescript const batcher = create({ fetcher: async (ids: number[]) => { return mock.usersByIds(ids); }, resolver: keyResolver("id"), scheduler: windowScheduler(33), }); let all = Promise.all([batcher.fetch(1), batcher.fetch(2), batcher.fetch(3), batcher.fetch(4)]); bacher.next() const users = await all //current batch of users [1,2,3,4] will be fetched immediately ``` -------------------------------- ### Integrate Batshit Devtools Source: https://context7.com/yornaath/batshit/llms.txt Shows how to configure named batchers and integrate the BatshitDevtools component into a React application. This allows developers to inspect batch sequences, timing, and responses in real-time. ```typescript import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; import BatshitDevtools from "@yornaath/batshit-devtools-react"; const userBatcher = create({ fetcher: async (ids: number[]) => { return fetch(`/api/users?ids=${ids.join(",")}`).then(r => r.json()); }, resolver: keyResolver("id"), scheduler: windowScheduler(10), name: "users", }); const App = () => { return (
); }; export default App; ``` -------------------------------- ### Fetch with Context using Memoizer in React Source: https://github.com/yornaath/batshit/blob/master/README.md Demonstrates how to use a memoizer with a batcher in a React hook to ensure a shared batcher instance is reused for a given context (e.g., an SDK instance). This prevents redundant batcher creations and ensures efficient fetching. ```typescript import { useQuery } from "@tanstack/react-query"; import { memoize } from "lodash-es"; import * as batshit from "@yornaath/batshit"; export const key = "markets"; const batcher = memoize((sdk: Sdk) => { return batshit.create({ name: key, fetcher: async (ids: number[]) => { const { markets } = await sdk.markets({ where: { marketId_in: ids, }, }); return markets; }, scheduler: batshit.windowScheduler(10), resolver: batshit.keyResolver("marketId"), }); }); export const useMarket = (marketId: number) => { const [sdk, id] = useSdk(); const query = useQuery( [id, key, marketId], async () => { if(sdk) { return batcher(sdk).fetch(marketId); } }, { enabled: Boolean(sdk), }, ); return query; }; ``` -------------------------------- ### Batcher with Max Batch Size Scheduler Source: https://github.com/yornaath/batshit/blob/master/README.md Sets up a batcher using `maxBatchSizeScheduler`. This scheduler exclusively focuses on the maximum number of items per batch (`maxBatchSize`). It will wait indefinitely until the batch size is met, without a time-based window constraint for initiating a new batch. ```typescript const batcher = batshit.create({ ... scheduler: maxBatchSizeScheduler({ maxBatchSize: 100, }), }); ``` -------------------------------- ### Batcher with Windowed Finite Batch Size Scheduler Source: https://github.com/yornaath/batshit/blob/master/README.md Configures a batcher using `windowedFiniteBatchScheduler`. This scheduler batches requests within a specified time window (`windowMs`) but also limits the maximum number of items in a single batch (`maxBatchSize`). A new batch is initiated once either the time window expires or the maximum batch size is reached. ```typescript const batcher = batshit.create({ ... scheduler: windowedFiniteBatchScheduler({ windowMs: 10, maxBatchSize: 100, }), }); ``` -------------------------------- ### Use windowScheduler for Fixed-Time Batching Source: https://context7.com/yornaath/batshit/llms.txt Configures a scheduler that collects requests over a fixed time window. Once the window expires, all accumulated requests are executed as a single batch. ```typescript import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; const users = create({ fetcher: async (ids: number[]) => { console.log(`Fetching users: ${ids.join(", ")}`); return fetch(`/api/users?ids=${ids.join(",")}`).then(r => r.json()); }, resolver: keyResolver("id"), scheduler: windowScheduler(10), }); const req1 = users.fetch(1); await delay(2); const req2 = users.fetch(2); await delay(3); const req3 = users.fetch(3); await delay(6); const req4 = users.fetch(4); const results = await Promise.all([req1, req2, req3, req4]); ``` -------------------------------- ### Integrate Batcher with React Query Source: https://github.com/yornaath/batshit/blob/master/packages/devtools/README.md Shows how to use a Batcher within a React component tree to consolidate multiple data fetches into a single network request. This pattern is particularly useful when rendering lists of components that each require individual data. ```typescript import { useQuery } from "react-query"; import { Batcher, windowScheduler } from "@yornaath/batshit"; const users = Batcher({ fetcher: async (ids) => client.users.where({ userId_in: ids }), resolver: keyResolver("id"), scheduler: windowScheduler(10), }); const useUser = (id: number) => useQuery(["users", id], async () => users.fetch(id)); const UserDetails = (props: { userId: number }) => { const { data } = useUser(props.userId); return
User: {data?.name}
; }; ``` -------------------------------- ### Implement Custom Resolver for Batshit Source: https://context7.com/yornaath/batshit/llms.txt Demonstrates how to define a custom resolver function to filter batch responses for specific query requirements. This is useful when the API response contains data for multiple queries and needs to be mapped back to individual requests. ```typescript import { create, windowScheduler } from "@yornaath/batshit"; type Post = { id: number; title: string; authorId: number }; const userPosts = create({ fetcher: async (queries: { authorId: number }[]) => { const authorIds = queries.map(q => q.authorId); const response = await fetch(`/api/posts?authorIds=${authorIds.join(",")}`); return response.json() as Promise; }, scheduler: windowScheduler(10), resolver: (allPosts, query) => allPosts.filter(post => post.authorId === query.authorId), }); const [alicesPosts, bobsPosts] = await Promise.all([ userPosts.fetch({ authorId: 1 }), userPosts.fetch({ authorId: 2 }), ]); ``` -------------------------------- ### Use KeyResolver for Array Responses Source: https://context7.com/yornaath/batshit/llms.txt Configures a batcher to extract items from an array response by matching a specific key. Supports an indexed mode for high-performance lookups in large datasets. ```typescript import { create, keyResolver } from "@yornaath/batshit"; type Product = { sku: string; name: string; price: number }; const products = create({ fetcher: async (skus: string[]) => { return fetch(`/api/products?skus=${skus.join(",")}`).then(r => r.json()); }, resolver: keyResolver("sku"), }); const bigCatalog = create({ fetcher: async (ids: number[]) => { return fetch(`/api/catalog?ids=${ids.join(",")}`).then(r => r.json()); }, resolver: keyResolver("id", { indexed: true }), }); ``` -------------------------------- ### Use windowedFiniteBatchScheduler for Hybrid Batching Source: https://context7.com/yornaath/batshit/llms.txt Combines time-based and size-based constraints to trigger batch execution. The batch fires either when the time window expires or when the maximum batch size is reached, whichever occurs first. ```typescript import { create, keyResolver, windowedFiniteBatchScheduler } from "@yornaath/batshit"; const users = create({ fetcher: async (ids: number[]) => { console.log(`Fetching batch of ${ids.length} users`); return fetch(`/api/users?ids=${ids.join(",")}`).then(r => r.json()); }, resolver: keyResolver("id"), scheduler: windowedFiniteBatchScheduler({ windowMs: 100, maxBatchSize: 50, }), }); const requests = Array.from({ length: 120 }, (_, i) => users.fetch(i + 1)); const results = await Promise.all(requests); ``` -------------------------------- ### Trigger immediate batch execution with batcher.next() Source: https://context7.com/yornaath/batshit/llms.txt Manually forces the execution of a pending batch, bypassing any configured scheduler delays. This is useful for time-sensitive operations where waiting for the window to expire is not feasible. ```typescript import { create, keyResolver, windowScheduler } from "@yornaath/batshit"; const users = create({ fetcher: async (ids: number[]) => { return fetch(`/api/users?ids=${ids.join(",")}`).then(r => r.json()); }, resolver: keyResolver("id"), scheduler: windowScheduler(1000), // Long 1-second window }); // Queue several requests const requests = Promise.all([ users.fetch(1), users.fetch(2), users.fetch(3), users.fetch(4), ]); // Don't wait 1 second - execute immediately users.next(); // Results available immediately instead of after 1 second const results = await requests; ``` -------------------------------- ### Aborting Batches with batcher.abort() Source: https://github.com/yornaath/batshit/blob/master/README.md Explains how to cancel the current batch of requests using `batcher.abort()`. The abort signal is passed down to the fetcher, allowing the underlying implementation (e.g., `fetch` API) to handle the cancellation gracefully. ```typescript test("aborting", async () => { const batcher = create({ fetcher: async (ids: number[], signal: AbortSignal) => { return fetch(`/users?ids=${ids.join(",")}`, { signal }) }, resolver: keyResolver("id"), }); let all = Promise.all([batcher.fetch(1), batcher.fetch(2), batcher.fetch(3), batcher.fetch(4)]); setTimeout(() => { batcher.abort(); }, 5) const error = await all.catch((error) => error); expect(error).toBeInstanceOf(DOMException); expect(error.message).toBe("Aborted"); }) ``` -------------------------------- ### Use IndexedResolver for Object Responses Source: https://context7.com/yornaath/batshit/llms.txt Configures a batcher to handle API responses that return data as a record object keyed by the query identifier. This is ideal for APIs that return maps rather than arrays. ```typescript import { create, indexedResolver } from "@yornaath/batshit"; type User = { username: string; email: string }; const users = create({ fetcher: async (usernames: string[]) => { const response = await fetch(`/api/users/batch`, { method: "POST", body: JSON.stringify({ usernames }), }); return response.json() as Promise>; }, resolver: indexedResolver(), }); ``` -------------------------------- ### Use bufferScheduler for Debounced Batching Source: https://context7.com/yornaath/batshit/llms.txt Implements a debounce-style scheduler that resets the timer whenever a new request is added. The batch only executes after a period of inactivity, ensuring all closely-spaced requests are grouped together. ```typescript import { create, keyResolver, bufferScheduler } from "@yornaath/batshit"; const users = create({ fetcher: async (ids: number[]) => { console.log(`Fetching users: ${ids.join(", ")}`); return fetch(`/api/users?ids=${ids.join(",")}`).then(r => r.json()); }, resolver: keyResolver("id"), scheduler: bufferScheduler(10), }); const req1 = users.fetch(1); await delay(5); const req2 = users.fetch(2); await delay(5); const req3 = users.fetch(3); await delay(5); const req4 = users.fetch(4); const results = await Promise.all([req1, req2, req3, req4]); ``` -------------------------------- ### Implement maxBatchSizeScheduler in TypeScript Source: https://context7.com/yornaath/batshit/llms.txt Configures a batcher to wait until a specific number of items are queued before triggering the fetcher. This is ideal for scenarios requiring full-batch processing to optimize API throughput. ```typescript import { create, keyResolver, maxBatchSizeScheduler } from "@yornaath/batshit"; const processor = create({ fetcher: async (items: string[]) => { console.log(`Processing batch of ${items.length} items`); return fetch("/api/process", { method: "POST", body: JSON.stringify(items), }).then(r => r.json()); }, resolver: keyResolver("id"), scheduler: maxBatchSizeScheduler({ maxBatchSize: 100, // Only process when we have 100 items }), }); // Batch won't execute until 100 items are queued const requests = Array.from({ length: 100 }, (_, i) => processor.fetch(`item-${i + 1}`) ); // Executes immediately when batch size reached const results = await Promise.all(requests); ``` -------------------------------- ### Abort pending batches with batcher.abort() Source: https://context7.com/yornaath/batshit/llms.txt Cancels the current pending batch and rejects all associated promises with an AbortError. It supports passing an AbortSignal to the fetcher to ensure underlying network requests are also cancelled. ```typescript import { create, keyResolver } from "@yornaath/batshit"; const users = create({ fetcher: async (ids: number[], signal: AbortSignal) => { return fetch(`/api/users?ids=${ids.join(",")}`, { signal }) .then(r => r.json()); }, resolver: keyResolver("id"), }); const requests = Promise.all([ users.fetch(1), users.fetch(2), users.fetch(3), ]); // Abort after 5ms setTimeout(() => { users.abort(); }, 5); try { await requests; } catch (error) { console.log(error.name); // "AbortError" } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.