React & React NativeEntity ListsExternal Data Integration

External Data Integration (infuseData)

The infuseData callback allows you to merge external data with entities fetched by Replyke. This is useful when your entities need additional information from external APIs or databases.

How It Works

When you provide an infuseData function to useEntityList, it:

  1. Receives the foreignId of each entity
  2. Fetches additional data from your external source
  3. Adds the external data under an infusion property
  4. Returns the combined data in the infusedEntities array

The original entities array remains unchanged, containing only Replyke’s data. External data is safely nested under the infusion property to prevent key conflicts.

Usage

import { useEntityList } from "@replyke/core";
 
const ProductFeed = () => {
  const entityList = useEntityList({
    listId: "product-feed",
    infuseData: async (foreignId) => {
      try {
        const response = await fetch(`/api/inventory/${foreignId}`);
        return response.ok ? await response.json() : null;
      } catch (error) {
        console.error(`Failed to fetch inventory for ${foreignId}:`, error);
        return null;
      }
    }
  });
 
  useEffect(() => {
    entityList.fetchEntities(
      { sortBy: "hot" },
      { sourceId: "products", limit: 20 }
    );
  }, []);
 
  return (
    <div>
      {entityList.infusedEntities.map((entity) => (
        <div key={entity.id}>
          <h2>{entity.title}</h2>
          <p>{entity.content}</p>
          {/* External data is under the 'infusion' property */}
          <p>Stock: {entity.infusion?.stock}</p>
          <p>Price: ${entity.infusion?.price}</p>
        </div>
      ))}
    </div>
  );
};

Performance

  • Data is fetched once per entity and cached
  • Failed fetches return null and don’t block other entities
  • The infuseData function is called automatically when new entities are loaded

Use Cases

Product Inventory

const infuseInventoryData = async (foreignId) => {
  const inventory = await fetch(`/api/inventory/${foreignId}`);
  return inventory.json(); // { stock: 25, price: 49.99, warehouse: "NYC" }
};

User Profiles

const infuseUserData = async (foreignId) => {
  const profile = await fetch(`/api/users/${foreignId}`);
  return profile.json(); // { avatar: "...", verified: true, followers: 1250 }
};

Analytics Data

const infuseAnalytics = async (foreignId) => {
  const stats = await fetch(`/api/analytics/${foreignId}`);
  return stats.json(); // { views: 5420, engagement: 0.12, trending: true }
};

Error Handling

The infuseData function should handle errors gracefully:

const infuseData = async (foreignId) => {
  try {
    const response = await fetch(`/api/external/${foreignId}`);
 
    if (!response.ok) {
      console.warn(`External data not found for ${foreignId}`);
      return null;
    }
 
    return await response.json();
  } catch (error) {
    console.error(`Failed to fetch external data for ${foreignId}:`, error);
    return null; // Return null on error, don't throw
  }
};

Data Structure

External data is safely nested under the infusion property to prevent conflicts with Replyke’s entity properties:

// Original entity from Replyke
const entity = {
  id: "123",
  foreignId: "product-456",
  title: "Amazing Widget",
  content: "A great product...",
  // ... other Replyke fields
};
 
// External data returned by infuseData
const externalData = {
  stock: 25,
  price: 49.99,
  warehouse: "NYC"
};
 
// Final result in infusedEntities
const infusedEntity = {
  id: "123",
  foreignId: "product-456",
  title: "Amazing Widget",
  content: "A great product...",
  // External data safely nested under 'infusion'
  infusion: {
    stock: 25,
    price: 49.99,
    warehouse: "NYC"
  }
};

Accessing Infused Data

Always access external data through the infusion property:

// ✅ Correct - access via infusion property
entity.infusion?.stock
entity.infusion?.price
entity.infusion?.warehouse
 
// ❌ Wrong - external data is not merged at root level
entity.stock // undefined
entity.price // undefined

Handling Missing Data

Since external data fetching can fail, always use optional chaining:

{entityList.infusedEntities.map(entity => (
  <div key={entity.id}>
    <h2>{entity.title}</h2>
    {entity.infusion ? (
      <div>
        <p>Stock: {entity.infusion.stock}</p>
        <p>Price: ${entity.infusion.price}</p>
      </div>
    ) : (
      <p>External data unavailable</p>
    )}
  </div>
))}