Skip to main content

Overview

The useArticle hook fetches a single news article from the Sui blockchain registry using its Walrus blob ID. It retrieves the full article content from Walrus storage and includes current engagement data (tips and comments).

Function Signature

function useArticle(blobId: string): UseQueryResult<NewsArticle | null, Error>

Parameters

blobId
string
required
The Walrus blob ID of the article to fetch. This is a unique identifier for the article stored in Walrus.

Return Type

Returns a React Query UseQueryResult object containing:
data
NewsArticle | null
The complete article object with full content and engagement data, or null if the article failed to load
id
string
Unique identifier for the article (same as blob_id)
blob_id
string
Walrus blob ID containing the article content
title
string
Article title
category
string
Article category (currently defaults to ‘General’)
source
'twitter' | 'rss' | 'onchain'
Source where the article originated
timestamp
number
Unix timestamp when the article was published
content
string
Full article content fetched from Walrus
summary
string
Article summary or excerpt
url
string
Original article URL if available
image
string
Article cover image URL
author
string
Article author name
totalTips
number
Total amount of tips received in SUI tokens
tipCount
number
Number of individual tips received
commentCount
number
Total number of comments on the article
isLoading
boolean
Whether the query is currently loading
error
Error | null
Error object if the query failed
refetch
() => Promise<void>
Function to manually refetch the article data

Usage

import { useArticle } from '@tuna/sdk';

function ArticleDetail({ blobId }: { blobId: string }) {
  const { data: article, isLoading, error } = useArticle(blobId);

  if (isLoading) return <div>Loading article...</div>;
  if (error) return <div>Error loading article</div>;
  if (!article) return <div>Article not found</div>;

  return (
    <article>
      {article.image && <img src={article.image} alt={article.title} />}
      <h1>{article.title}</h1>
      
      <div>
        <span>By {article.author}</span>
        <span>Source: {article.source}</span>
        <time>{new Date(article.timestamp * 1000).toLocaleDateString()}</time>
      </div>

      <p>{article.summary}</p>
      <div dangerouslySetInnerHTML={{ __html: article.content || '' }} />
    </article>
  );
}

Query Configuration

The hook is configured with the following React Query options:
  • Query Key: ['article', blobId]
  • Enabled: Only when blobId is provided (truthy)
  • Caching: Automatically cached by React Query based on the blob ID
The query will not execute if blobId is an empty string or undefined. This prevents unnecessary API calls.

Error Handling

If the article fails to fetch (e.g., invalid blob ID or Walrus error), the hook returns null for the data field and logs the error to the console.
import { useArticle } from '@tuna/sdk';

function SafeArticleView({ blobId }: { blobId: string }) {
  const { data: article, error } = useArticle(blobId);

  if (error) {
    console.error('Article fetch error:', error);
    return <div>Unable to load article. Please try again later.</div>;
  }

  if (article === null) {
    return <div>Article not found or failed to load.</div>;
  }

  return <div>{article.title}</div>;
}

Combining with Comments

The useArticle hook works seamlessly with comment hooks:
import { useArticle, useArticleComments } from '@tuna/sdk';

function FullArticleView({ blobId }: { blobId: string }) {
  const { data: article, isLoading: articleLoading } = useArticle(blobId);
  const { data: comments, isLoading: commentsLoading } = useArticleComments(blobId);

  if (articleLoading) return <div>Loading...</div>;
  if (!article) return <div>Article not found</div>;

  return (
    <div>
      <article>
        <h1>{article.title}</h1>
        <p>{article.content}</p>
        <p>{article.commentCount} comments</p>
      </article>

      <section>
        <h2>Comments</h2>
        {commentsLoading ? (
          <p>Loading comments...</p>
        ) : (
          comments?.map((comment) => (
            <div key={comment.id}>
              <p>{comment.text}</p>
            </div>
          ))
        )}
      </section>
    </div>
  );
}

Engagement Data Updates

Engagement data (tips and comment count) is fetched fresh each time the query runs. To see updated engagement:
import { useArticle } from '@tuna/sdk';

function ArticleWithRefresh({ blobId }: { blobId: string }) {
  const { data: article, refetch, isLoading } = useArticle(blobId);

  return (
    <div>
      <h1>{article?.title}</h1>
      
      <div>
        <span>💰 {article?.totalTips} SUI</span>
        <span>💬 {article?.commentCount} comments</span>
      </div>

      <button onClick={() => refetch()} disabled={isLoading}>
        {isLoading ? 'Refreshing...' : 'Refresh Engagement'}
      </button>
    </div>
  );
}

Performance Considerations

  • The hook fetches both blockchain data (engagement) and Walrus data (content) in a single query
  • Data is automatically cached by React Query based on the blob ID
  • Subsequent renders with the same blob ID will use cached data
  • Failed fetches return null instead of throwing, allowing graceful error handling

See Also

Build docs developers (and LLMs) love