Fetchye
✨ If you know how to use Fetch, you know how to use Fetchye [fetch-yae]. Simple React Hooks, Centralized Cache, Infinitely Extensible.
Install / Use
/learn @americanexpress/FetchyeREADME
If you know how to use Fetch, you know how to use Fetchye [fetch-yae]. Simple React Hooks, Centralized Cache, Infinitely Extensible.
// ...
import { useFetchye } from 'fetchye';
const MyComponent = () => {
const { isLoading, data } = useFetchye('http://example.com/api/profile');
return (
!isLoading && (
<p>{data.body.name}</p>
)
);
};
📖 Table of Contents
✨ Features
- ES6 Fetch powered by React Hooks
- Pure React or Redux Shared Cache modes available
- Headless per-Hook Cache Mode available
- SSR-friendly
⬇️ Install & Setup
Contents
Quick Install
💡 Makes use of Headless per-Hook Cache Mode
Pros
- Painless and Quick
Cons
- No shared caching
- No de-duplication of API calls
Just install and do useFetchye. Thats it!
npm i -S fetchye
// ...
import { useFetchye } from 'fetchye';
const MyComponent = () => {
const { isLoading, data } = useFetchye('http://example.com/api/profile');
return (
!isLoading && (
<p>{data?.body.name}</p>
)
);
};
FetchyeProvider Install
💡 When you want a central cache but no extra dependencies
Pros
- Easy
- Shared Cache
- De-duplication of API calls
Cons
- No Redux Dev Tools for debugging and cache inspection
- Limited centralized server-side data hydration support
Install fetchye:
npm i -S fetchye
Add the <FetchyeProvider /> component:
import { FetchyeProvider } from 'fetchye';
const ParentComponent = ({ children }) => (
<FetchyeProvider>
{/* Use your Router to supply children components containing useFetchye */}
{children}
</FetchyeProvider>
);
In a child React Component, do useFetchye queries:
// ...
import { useFetchye } from 'fetchye';
const MyComponent = () => {
const { isLoading, data } = useFetchye('http://example.com/api/profile');
return (
!isLoading && (
<p>{data?.body.name}</p>
)
);
};
FetchyeReduxProvider Install
💡 When you want a central cache integrated with a Redux based project
Pros
- Easy if you know Redux
- Shared Cache
- De-duplication of API calls
- Redux Dev Tools for debugging and cache inspection
- Excellent centralized server-side data hydration support
Cons
- More steps and dependencies
Add fetchye and its needed optional dependencies:
npm i -S fetchye redux react-redux
Add the <FetchyeReduxProvider /> component under the Redux <Provider />:
import React from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { FetchyeReduxProvider } from 'fetchye-redux-provider';
import { SimpleCache } from 'fetchye';
const fetchyeCache = SimpleCache({
// Need to tell Fetchye where the cache reducer will be located
cacheSelector: (state) => state,
});
const store = createStore(fetchyeCache.reducer);
const ParentComponent = ({ children }) => (
<Provider store={store}>
<FetchyeReduxProvider cache={fetchyeCache}>
{/* Use your Router to supply children components containing useFetchye */}
{children}
</FetchyeReduxProvider>
</Provider>
);
In a child React Component, do useFetchye queries:
// ...
import { useFetchye } from 'fetchye';
const MyComponent = () => {
const { isLoading, data } = useFetchye('http://example.com/api/profile');
return (
!isLoading && (
<p>{data.body.name}</p>
)
);
};
One App Install
💡 For when you use the One App Micro-Frontend Framework
Pros
- Shared Cache
- De-duplication of API calls
- Redux Dev Tools for debugging and cache inspection
- Excellent centralized server-side data hydration support
- Shared Cache between Micro Frontend Holocron Modules
- Immutable Redux State
- Minimal configuration
Cons
- More steps and dependencies
npm i -S fetchye fetchye-one-app
fetchye-one-app provides pre-configured provider, cache, oneFetchye and oneCacheSelector to ensure that all modules use the same cache and reduce the chance for cache misses. These all have restricted APIs to reduce the chance for misconfiguration however if you require more control/customization use ImmutableCache, FetchyeReduxProvider and makeServerFetchye. Please bear in mind that this can impact modules which are do not use the same configuration.
Add the <OneFetchyeProvider /> component from fetchye-one-app to your Root Holocron Module, and add the reducer from OneCache scoped under fetchye:
// ...
import { combineReducers } from 'redux-immutable';
import { OneFetchyeProvider, OneCache } from 'fetchye-one-app';
const MyModuleRoot = ({ children }) => (
<>
{ /* OneFetchyeProvider is configured to use OneCache */}
<OneFetchyeProvider>
{/* Use your Router to supply children components containing useFetchye */}
{children}
</OneFetchyeProvider>
</>
);
// ...
MyModuleRoot.holocron = {
name: 'my-module-root',
reducer: combineReducers({
// ensure you scope the reducer under "fetchye", this is important
// to ensure that child modules can make use of the single cache
fetchye: OneCache().reducer,
// ... other reducers
}),
};
In a child React Component or Holocron Module, do useFetchye queries:
// ...
import { useFetchye } from 'fetchye';
const MyComponent = () => {
const { isLoading, data } = useFetchye('http://example.com/api/profile');
return (
!isLoading && (
<p>{data?.body.name}</p>
)
);
};
This minimal configuration works as the provider, cache and makeOneServerFetchye, mentioned later, all follow expected conventions.
🤹 Usage
Real-World Example
import React from 'react';
import { useFetchye } from 'fetchye';
const BookList = ({ genre }) => {
const { isLoading, error, data } = useFetchye(`http://example.com/api/books/?genre=${genre}`, {
headers: {
'X-Some-Tracer-Id': 1234,
},
});
if (isLoading) {
return (<p>Loading...</p>);
}
if (error || data.status !== 200) {
return (<p>Oops!</p>);
}
return (
<>
<h1>Books by {genre}</h1>
<ul>
{data.body.map((book) => (
<li key={book.id}>{book.title} by {book.author}</li>
))}
</ul>
</>
);
};
Deferred execution
When you need to delay execution of a useFetchye call, you may use
{ defer: true } option. This is great for forms:
import React from 'react';
import { useFetchye } from 'fetchye';
const NewBookForm = () => {
const { formData, onChange } = useSomeFormHandler();
const { isLoading, run } = useFetchye('http://example.com/api/books', {
// include defer here
defer: true,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...formData,
}),
});
const onSubmit = async (event) => {
event.preventDefault();
const { data, error } = await run();
// Check to make sure no error and data.status === 200 for success
};
return (
<form onSubmit={onSubmit}>
{/* ...form elements using onChange */}
{/* Hide Submit button when sending POST request */}
{!isLoading && <button type="submit">Submit</button>}
</form>
);
};
Abort Inflight Requests
When you neeed to abort the execution of requests inflight, passing a signal from the Abort Controller API to useFetchye as an option will enable this.
Considering useFetchye is a wrapper around fetch, passing a signal is the same and provides the same functionality as demonstrated below.
import React, { useEffect } from 'react';
import { useFetchye } from 'fetchye';
const AbortComponent = () => {
const controller = new AbortController();
useFetchye('http://example.com/api/books', { signal: controller.signal });
// eslint-disable-next-line react-hooks/exhaustive-deps -- sample code.
useEffect(() => () => controller.abort(), []);
return (
<div>
<h1>abortable component</h1>
</div>
);
};
Instead of setting up a useEffect within the component it's possible to pass a hook to signal using packages such as
use-unmount-signal.
Sequential API Execution
Passing the 'isLoading' value from one useFetchye call to the 'defer' field of the next will prevent the second call from being made until the first has loaded.
To ensure the second api call is properly formed, you should also check that the data you expect from the first call exists:
import React from 'react';
import { useFetchye } from 'fetchye';
const MyFavoriteBook = () => {
const {
isLoading: loadingProfile,
error: profileError,
data: profile,
} = useFetchye('http://example.com/api/profile');
const profileHasBookId = !loadingProfile && profile?.body?.favoriteBookId;
const {
isLoading: loadingBook,
error: bookError,
data: favoriteBook,
} = useFetchye('http://example.com/api/books', {
Related Skills
bluebubbles
338.7kUse when you need to send or manage iMessages via BlueBubbles (recommended iMessage integration). Calls go through the generic message tool with channel="bluebubbles".
node-connect
338.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
slack
338.7kUse when you need to control Slack from OpenClaw via the slack tool, including reacting to messages or pinning/unpinning items in Slack channels or DMs.
frontend-design
83.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
