> ## Documentation Index
> Fetch the complete documentation index at: https://replyke-feat-push-rich-payload-fields.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

## Entity Lists

Entity lists in Replyke provide powerful feed and list management functionality using Redux state management. The `useEntityList` hook allows you to create, manage, and filter lists of entities with built-in pagination, caching, and real-time updates.

## Quick Start

```typescript theme={null}
import { useEntityList } from "@replyke/core";

function MyFeed() {
  const entityList = useEntityList({
    listId: "main-feed",
    infuseData: optionalExternalDataFunction
  });

  // Load initial data
  useEffect(() => {
    entityList.fetchEntities(
      { sortBy: "hot", timeFrame: "day" },
      { sourceId: "posts", limit: 20 }
    );
  }, []);

  return (
    <div>
      {entityList.loading && <div>Loading...</div>}
      {entityList.entities.map(entity => (
        <div key={entity.id}>{entity.title}</div>
      ))}
      {entityList.hasMore && (
        <button onClick={entityList.loadMore}>Load More</button>
      )}
    </div>
  );
}
```

## Core Concepts

### List IDs

Each entity list requires a unique `listId`. This is a client-side identifier that allows multiple independent lists to coexist in your application with their own state, filters, and cached data.

Think of `listId` as creating separate "instances" of entity lists in your Redux store. Each list maintains:

* Its own entities array
* Independent filter states
* Separate loading states
* Individual pagination state

```typescript theme={null}
// Different lists for different UI purposes
const mainFeed = useEntityList({ listId: "main-feed" });
const userProfile = useEntityList({ listId: `user-${userId}` });
const searchResults = useEntityList({ listId: "search-results" });
const trending = useEntityList({ listId: "trending-posts" });
```

**Common listId patterns:**

* Static feeds: `"main-feed"`, `"trending"`, `"popular"`
* User-specific: `"user-${userId}"`, `"user-${userId}-favorites"`
* Search/filters: `"search-${query}"`, `"category-${categoryId}"`
* Temporary lists: `"modal-feed"`, `"drawer-content"`

**Important:** The `listId` is purely for client-side state management and doesn't affect which entities are fetched from the server. Use `sourceId` in your fetch configuration to control which entities are returned from Replyke.

### Source IDs (Critical Concept)

<Warning>
  **Always use `sourceId` when creating entities.** The `sourceId` logically separates different types of content within your project, preventing them from mixing inappropriately.
</Warning>

#### Why sourceId Matters

Imagine you're building an image-sharing app but also have a product blog. Without `sourceId`:

* Your image feed could suddenly show blog articles
* Blog subscribers might see random user photos
* Content gets mixed unintentionally

With proper `sourceId` separation:

```typescript theme={null}
// When creating entities
await createEntity({
  title: "Beautiful sunset",
  content: "Amazing photo from today",
  sourceId: "image-posts" // Images stay in image feeds
});

await createEntity({
  title: "Product Update v2.0",
  content: "New features and improvements...",
  sourceId: "blog-articles" // Articles stay in blog feeds
});
```

#### Fetching by sourceId

```typescript theme={null}
// Image feed - only gets images
const imageFeed = useEntityList({ listId: "main-images" });
imageFeed.fetchEntities(
  { sortBy: "hot" },
  { sourceId: "image-posts" }
);

// Blog feed - only gets articles
const blogFeed = useEntityList({ listId: "blog-feed" });
blogFeed.fetchEntities(
  { sortBy: "new" },
  { sourceId: "blog-articles" }
);
```

#### Best Practices for sourceId

<Tip title="Best Practices for sourceId">
  **✅ Always use sourceId, even initially:**

  ```typescript theme={null}
  // Good - even if you only have one content type now
  { sourceId: "user-posts" }

  // Bad - will cause problems later
  { sourceId: null }
  ```

  **✅ Use descriptive names:**

  * `"user-posts"` - User-generated content
  * `"blog-articles"` - Official blog posts
  * `"product-reviews"` - Product reviews
  * `"help-docs"` - Documentation content
  * `"announcements"` - Company announcements
</Tip>

### Filters vs Configuration

Entity lists accept two types of parameters:

* **Filters**: User-controlled parameters like sorting, time frames, and content filters
* **Configuration**: System-level parameters like `sourceId` and pagination `limit`

```typescript theme={null}
entityList.fetchEntities(
  // Filters (what content to show)
  {
    sortBy: "hot",
    timeFrame: "week",
    userId: "specific-user"
  },
  // Configuration (how to fetch)
  {
    sourceId: "blog-posts", // Critical: separates content types
    limit: 25
  }
);
```

## Hook Interface

```typescript theme={null}
interface UseEntityListProps {
  listId: string;
  infuseData?: (foreignId: string) => Promise<Record<string, any> | null>;
}

interface UseEntityListValues {
  // Data
  entities: Entity[];
  infusedEntities: (Entity & Record<string, any>)[];

  // State
  loading: boolean;
  hasMore: boolean;

  // Current filters (read-only)
  sortBy: EntityListSortByOptions | null;
  timeFrame: TimeFrame | null;
  sourceId: string | null;
  userId: string | null;
  followedOnly: boolean;
  keywordsFilters: KeywordsFilters | null;
  titleFilters: TitleFilters | null;
  contentFilters: ContentFilters | null;
  attachmentsFilters: AttachmentsFilters | null;
  locationFilters: LocationFilters | null;
  metadataFilters: MetadataFilters | null;

  // Actions
  fetchEntities: (filters, config?, options?) => void;
  loadMore: () => void;
  createEntity: (props) => Promise<Entity | undefined>;
  deleteEntity: (props) => Promise<void>;
}
```

## Available Filters

Entity lists support comprehensive filtering options:

* **sortBy**: `"hot"`, `"new"`, `"top"`, `"controversial"`
* **timeFrame**: `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`
* **userId**: Filter by specific user
* **followedOnly**: Show only followed users' content
* **Content filters**: Title, content, keywords, attachments, location, metadata

See the filters documentation for detailed examples of each filter type.

## Advanced Features

### External Data Integration

Use the `infuseData` callback to merge external data with entities:

```typescript theme={null}
const entityList = useEntityList({
  listId: "products",
  infuseData: async (foreignId) => {
    const inventory = await fetch(`/api/inventory/${foreignId}`);
    return inventory.json();
  }
});

// Access merged data
entityList.infusedEntities.forEach(entity => {
  console.log(entity.title); // From Replyke
  console.log(entity.infusion?.stock); // From external API (under 'infusion')
});
```

### Dynamic Filtering

Update filters by calling `fetchEntities` with new parameters:

```typescript theme={null}
const handleSearch = (query: string) => {
  entityList.fetchEntities({
    sortBy: "new",
    titleFilters: { includes: [query] }
  }, undefined, {
    immediate: true,
    clearImmediately: true
  });
};
```

### Multiple Lists

Create multiple independent lists for different use cases:

```typescript theme={null}
function Dashboard() {
  const hotPosts = useEntityList({ listId: "hot-posts" });
  const newPosts = useEntityList({ listId: "new-posts" });
  const userPosts = useEntityList({ listId: `user-${userId}` });

  useEffect(() => {
    hotPosts.fetchEntities({ sortBy: "hot" });
    newPosts.fetchEntities({ sortBy: "new" });
    userPosts.fetchEntities({ sortBy: "new", userId });
  }, []);

  return (
    <div>
      <div>Hot Posts: {hotPosts.entities.length}</div>
      <div>New Posts: {newPosts.entities.length}</div>
      <div>User Posts: {userPosts.entities.length}</div>
    </div>
  );
}
```

## Error Handling

The hook automatically handles errors and provides loading states:

```typescript theme={null}
const entityList = useEntityList({ listId: "my-feed" });

// Check loading state
if (entityList.loading) {
  return <div>Loading...</div>;
}

// Handle empty state
if (!entityList.loading && entityList.entities.length === 0) {
  return <div>No posts found</div>;
}
```

## Performance Notes

* Entity lists use Redux for state management, providing automatic caching and persistence
* The `fetchEntities` function includes debouncing for filter changes (800ms delay)
* Use `options.immediate: true` to bypass debouncing when needed
* Each list maintains independent state based on its `listId`
