Integrating Bee-JS with React Applications for Swarm Decentralized Storage
Bee-JS provides the official JavaScript SDK for React developers to upload, download, and manage files on the Swarm decentralized storage network through a promise-based API that integrates seamlessly with modern React patterns.
The ethersphere/awesome-swarm repository identifies Bee-JS as the primary JavaScript SDK for interacting with Swarm's Bee nodes via REST API. By integrating Bee-JS into a React application, you can build declarative UI components that handle decentralized file storage directly from the browser while maintaining reactive state management and upload progress tracking.
Architecture Overview
A typical Bee-JS React integration follows a layered architecture that separates presentation logic from storage operations.
| Component | Role | Interaction |
|---|---|---|
| React UI | Renders forms, buttons, progress indicators, and content viewers. | Invokes Bee-JS methods through custom hooks and event handlers. |
Bee-JS Client (@ethersphere/bee-js) |
Wraps the Bee HTTP API, handling authentication, request signing, and response parsing. | Exposes methods including uploadFile, downloadFile, uploadDirectory, getFeed, and setFeed. |
| Bee Node | The Swarm storage backend that persists chunks, manifests, and feeds. | Receives HTTP calls from Bee-JS and returns Swarm hashes (e.g., bzz://<hash>). |
| State Management | Tracks upload progress, Swarm references, and error states. | Updated by React hooks that wrap asynchronous Bee-JS operations. |
The upload flow works as follows: a user selects a file in a React component, a custom hook calls bee.uploadFile(), Bee-JS streams the data to the Bee node's /files endpoint, and the hook updates React state with the returned Swarm hash to trigger a UI re-render.
Setting Up Bee-JS in Your React Project
Installation
Install the official SDK package via npm:
npm install @ethersphere/bee-js
Client Initialization
Create a centralized client instance to avoid duplicate initialization and share configuration across components. In src/beeClient.ts, instantiate the Bee class with your node endpoint:
import { Bee } from '@ethersphere/bee-js';
export const bee = new Bee('http://localhost:1633', {
// Optional: specify API token if your node requires authentication
// apiKey: process.env.REACT_APP_BEE_API_KEY,
});
This client wraps the Bee HTTP API and exposes methods for file operations, feed management, and postage batch handling.
Uploading Files to Swarm with React Hooks
Creating the useBeeUpload Hook
Encapsulate upload logic in a reusable hook to keep components declarative. In src/hooks/useBeeUpload.ts, wrap bee.uploadFile with progress tracking:
import { useState, useCallback } from 'react';
import { bee } from '../beeClient';
export function useBeeUpload() {
const [hash, setHash] = useState<string | null>(null);
const [progress, setProgress] = useState<number>(0);
const [error, setError] = useState<string | null>(null);
const upload = useCallback(
async (file: File) => {
try {
setError(null);
setProgress(0);
const response = await bee.uploadFile(file, {
onUploadProgress: (event) => {
const percent = Math.round((event.loaded * 100) / event.total);
setProgress(percent);
},
});
setHash(response.reference); // Swarm hash, e.g., `bzz://...`
} catch (e: any) {
setError(e.message);
}
},
[],
);
return { hash, progress, error, upload };
}
The onUploadProgress callback enables real-time progress updates by calculating the percentage from the event's loaded and total properties.
Building the UploadForm Component
Create a presentational component in src/components/UploadForm.tsx that consumes the hook:
import React, { ChangeEvent } from 'react';
import { useBeeUpload } from '../hooks/useBeeUpload';
export function UploadForm() {
const { hash, progress, error, upload } = useBeeUpload();
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) upload(file);
};
return (
<div>
<input type="file" onChange={handleChange} />
{progress > 0 && <p>Uploading… {progress}%</p>}
{hash && (
<p>
Uploaded! Swarm address:{' '}
<a href={`https://bzz.link/${hash}`} target="_blank" rel="noopener noreferrer">
{hash}
</a>
</p>
)}
{error && <p style={{ color: 'red' }}>Error: {error}</p>}
</div>
);
}
This component handles file selection, delegates the upload to the hook, and conditionally renders progress indicators or the final Swarm reference.
Downloading and Displaying Swarm Content
The useBeeDownload Hook
For retrieving content, create src/hooks/useBeeDownload.ts to wrap bee.downloadFile:
import { useState, useCallback } from 'react';
import { bee } from '../beeClient';
export function useBeeDownload() {
const [dataUrl, setDataUrl] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const download = useCallback(async (hash: string) => {
try {
setError(null);
const file = await bee.downloadFile(hash);
const blob = new Blob([file.fileData], { type: file.contentType });
setDataUrl(URL.createObjectURL(blob));
} catch (e: any) {
setError(e.message);
}
}, []);
return { dataUrl, error, download };
}
The hook converts the downloaded fileData into a Blob URL suitable for rendering in browser elements like images or download links.
Rendering Downloaded Images
In src/components/ImageViewer.tsx, use the hook to fetch and display Swarm-hosted images:
import React, { useEffect } from 'react';
import { useBeeDownload } from '../hooks/useBeeDownload';
export function ImageViewer({ hash }: { hash: string }) {
const { dataUrl, error, download } = useBeeDownload();
useEffect(() => {
download(hash);
}, [hash, download]);
if (error) return <p style={{ color: 'red' }}>{error}</p>;
if (!dataUrl) return <p>Loading…</p>;
return <img src={dataUrl} alt="Swarm content" style={{ maxWidth: '100%' }} />;
}
This pattern separates data fetching from presentation, allowing the component to handle loading and error states declaratively.
Summary
Integrating Bee-JS with React applications for Swarm decentralized storage requires three core layers:
- Centralized Client Configuration: Initialize the
Beeclass once insrc/beeClient.tsto manage API endpoints and authentication tokens. - Custom Hooks for Async Operations: Wrap
uploadFileanddownloadFilein hooks likeuseBeeUploadanduseBeeDownloadto handle progress tracking, error states, and Blob conversion. - Declarative UI Components: Build presentational components that consume these hooks, rendering file inputs, progress bars, and content viewers based on the Swarm hashes returned by the Bee node.
This architecture aligns with React's component-driven model while leveraging Bee-JS's promise-based API to interact with the Swarm network as documented in the ethersphere/awesome-swarm repository.
Frequently Asked Questions
How does Bee-JS handle authentication with Bee nodes?
Bee-JS supports API key authentication through the apiKey configuration option passed to the Bee constructor. If your node requires a gateway token for restricted endpoints, include it in the client initialization in src/beeClient.ts to ensure all requests include the proper authentication headers.
Can I track upload progress when storing files on Swarm?
Yes. The uploadFile method accepts an onUploadProgress callback that receives progress events containing loaded and total byte counts. By calculating the percentage in your React hook and updating state, you can drive progress indicators in your UI components as demonstrated in the useBeeUpload implementation.
What Swarm hash format does Bee-JS return after uploading?
Bee-JS returns a Swarm reference (hash) in the response.reference property, which represents the content-addressed identifier for your stored data. You can use this hash to construct gateway URLs like https://bzz.link/${hash} for browser access or pass it to downloadFile for retrieval within your application.
Is Bee-JS compatible with React Server Components or Next.js App Router?
Bee-JS is designed for browser and Node.js environments, but its file handling methods expect browser APIs like File and Blob for uploads. For React Server Components, invoke Bee-JS methods in Client Components (using the "use client" directive) or in API routes where you can handle multipart form data and stream responses appropriately.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →