In the social.plus TypeScript SDK, we have the concept of Live Object and Live Collection. Live Object is represented by an instance of social.plus Object. It helps to observe changes in a single object whereas Live Collection is represented by an instance of social.plus LiveCollection. It helps to observe changes in a list of objects. SDK handles lots of data received from various sources. Data can be present in the local cache. It may also be queried from the server or received from real-time events. What this means is that the same data is constantly updating. The data that you are accessing at the moment can get updated and become out of sync. Live Object and Live Collection help in syncing data so you will always get the most recent one. New data gets automatically collected every time when there is an update and the user need not refresh to get the recent data.
Examples: Amity.Post for single objects or Amity.LiveCollection<Amity.Post> for collections.

How it Works

SDK handles lots of data received from various sources. Data can be present in local cache. It might also be queried from the server or received from some real-time events. What this means is that same data is constantly updating. The data that you are accessing at the moment can get updated by other sources and becomes out of sync. Live Object and Live Collection help in syncing the data so you will always get the most recent one. Whenever the data updates, you will be notified through subscribable objects and collections. New data gets automatically collected everytime when there is an updation and user need not refresh to get the recent data.

Data Sources

Local Cache

Data present in local storage

Server Queries

Data queried from the server

Real-time Events

Data received from real-time events

Live Object

Although live objects were introduced prior to v6. All getter methods for singular objects (example getPost) will now return a subscribe-able object. This means that if an object gets updated and you have subscribed to real-time events, the object will get updated automatically via real-time events. If for your use case, you don’t require any real-time updates, you can unsubscribe immediately.
For further information about Live Object, please visit Live Object page.

Getting Real Time Updates for an Object

import { PostRepository, subscribeTopic, getPostTopic } from '@amityco/ts-sdk';
import { FC, useEffect, useState } from 'react';

const disposers: Amity.Unsubscriber[] = [];

const GetPost: FC<{ postId: string }> = ({ postId }) => {
  const [post, setPost] = useState<Amity.Post>();

  useEffect(() => {

    const unsubscribePost = PostRepository.getPost(postId, ({ data }) => {
     const { post, loading, error } = data
     
     if (post) {
       /*
       * This step is important if you wish to recieve real time updates
       * Here, you are letting the server know that you wish to recieve real time
       * updates regarding this post
       */
       disposers.push(subscribeTopic(getPostTopic(post)))
       
       setPost(post)
     }
    });
    
    disposers.push(unsubscribePost);
  }, [postId]);

  return null;
};

Getting the object only once

import { PostRepository } from '@amityco/ts-sdk';
import { FC, useEffect, useState } from 'react';

const GetPostOnce: FC<{ postId: string }> = ({ postId }) => {
  const [post, setPost] = useState<Amity.Post>();

  useEffect(() => {
    const unsubscribePost = PostRepository.getPost(postId, ({ data }) => {
     const { post, loading, error } = data
     
     if (post) {       
       setPost(post)
     }
    });
    
    unsubscribePost()
  }, [postId]);

  return null;
};

## Live Collection

Although live collections were introduced prior to v6. All query methods for the collection of objects (example getPosts) will now return a subscribe-able collection.

This means that if an object in the collection gets updated and you have subscribed to real-time events, the collection will get updated automatically via real-time events.

If for your use case, you don't require any real-time updates, you can unsubscribe immediately. Similar to the live objects above.

<Info>
For further information about Live Collection, please visit Live Collection page.
</Info>

### Getting Real-Time updates for a collection

```typescript
import {
  PostRepository,
  subscribeTopic,
  getUserTopic,
  getCommunityTopic,
  SubscriptionLevels,
} from '@amityco/ts-sdk';
import { FC, useEffect, useState } from 'react';

const disposers: Amity.Unsubscriber[] = [];

const GetPosts: FC<{ targetId: string; targetType: string }> = 
({ targetId, targetType }) => {
  const [posts, setPosts] = useState<Amity.Post[]>();

  useEffect(() => {
    const unsubscribe = PostRepository.getPosts(
      { targetId, targetType },
      ({ data: posts, onNextPage, hasNextPage, loading, error }) => {
        setPosts(posts);
        /*
         * this is only required if you want real time updates for each
         * post in the collection
         */
        subscribePostTopic(targetType, targetId);
      },
    );

    disposers.push(unsubscribe);

    return () => {
      disposers.forEach(fn => fn());
    };
  });

  return null;
};

const subscribePostTopic = (targetType: string, targetId: string) => {
  if (isSubscribed) return;

  if (targetType === 'user') {
    const user = {} as Amity.User; // use getUser to get user by targetId
    disposers.push(
      subscribeTopic(getUserTopic(user, SubscriptionLevels.POST), () => {
        // use callback to handle errors with event subscription
      }),
    );
    return;
  }

  if (targetType === 'community') {
    // use getCommunity to get community by targetId
    const community = {} as Amity.Community; 
    disposers.push(
      subscribeTopic(getCommunityTopic(community, SubscriptionLevels.POST), () => {
        // use callback to handle errors with event subscription
      }),
    );
  }
};

Getting paginated collection without real-time updates

import {
  PostRepository,
  subscribeTopic,
  getUserTopic,
  getCommunityTopic,
  SubscriptionLevels,
} from '@amityco/ts-sdk';
import { FC, useEffect, useState } from 'react';

const GetPosts: FC<{ targetId: string; targetType: string }> = 
({ targetId, targetType }) => {
  const [posts, setPosts] = useState<Amity.Post[]>();

  useEffect(() => {
    const unsubscribe = PostRepository.getPosts(
      { targetId, targetType },
      ({ data: posts, onNextPage, hasNextPage, loading, error }) => {
        if (posts)
          setPosts(posts);
        
        // to get next page use onNextPage()
      },
    );

    unsubscribe()
  });

  return null;
};

## Best Practices

<AccordionGroup>
  <Accordion title="Memory Management">
    **Always Clean Up**: Prevent memory leaks by properly disposing of subscriptions and unsubscribers.
    
    ```typescript
    // Use a disposer pattern
    const disposers: Amity.Unsubscriber[] = [];
    
    useEffect(() => {
      // Add subscriptions
      disposers.push(PostRepository.getPost(postId, callback));
      disposers.push(subscribeTopic(getPostTopic(post)));
      
      return () => {
        // Clean up all subscriptions
        disposers.forEach(dispose => dispose());
      };
    }, []);