SkillAgentSearch skills...

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/Fetchye

README

<h1 align="center"> <img src="https://github.com/americanexpress/fetchye/raw/main/fetchye.png" alt="Fetchye - One Amex" width="50%" /> </h1>

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>
    )
  );
};

🏖️Try this out on Codesandbox

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>
    )
  );
};

🏖️Try this out on Codesandbox

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>
    )
  );
};

🏖️Try this out on Codesandbox

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

View on GitHub
GitHub Stars45
CategoryDevelopment
Updated1d ago
Forks26

Languages

JavaScript

Security Score

95/100

Audited on Mar 26, 2026

No findings