How to use InterPlanetary File System in React?

Introduction

The Internet changed how we share and get info, but it has some flaws, like relying too much on big central servers. That's where IPFS, or InterPlanetary File System, comes in. It's a cool new way of storing and getting files that don't need just one server. It's like spreading pieces of a puzzle all over the world, so even if one piece is missing, you can still finish the puzzle. IPFS makes the web more decentralized and stronger.

IPFS

IPFS, or the InterPlanetary File System, is like a supercharged version of the web. Instead of storing files on one central server, IPFS breaks files into tiny pieces and spreads them across a network of computers. This means files can be stored and accessed faster, and they're more secure because there's no single point of failure. Plus, IPFS uses something called content addressing, which means files are identified by their unique content, not their location.

React

React is a JavaScript library for building user interfaces, developed by Facebook. It's popular among developers because it allows them to create interactive and dynamic web applications with ease. React uses a component-based architecture, which makes it easy to reuse code and build complex interfaces. Its virtual DOM (Document Object Model) also helps in efficiently updating the UI, leading to better performance. As a result, React has become one of the most widely used frameworks for web development. Let's see how we can integrate these by creating a basic web3 application.

Creating React project

If you want to learn more about React, explore this tutorial. Let's create a new React project. React is a JavaScript library for building user interfaces. To make it easier to start a new React project, there's a tool called Create React App. It sets up a new React project for us with all the necessary files and configurations. In your terminal or command prompt, type the following command to create a new React project using the Create React App.

npx create-react-app ipfs-project

you will see the following output that confirms that your react app has been successfully created.

create-react-app

Now navigate to the ipfs-project directory and open this project in your favorite IDE. Now create a new react component in the 'src' directory named 'List.js' and paste the following code in that file. In this component, we will add functionality to upload an image and display the uploaded image into the card and its CID.

import React, { useState } from "react";
import './List.css';
import TextDisplayBox from './TextDisplayBox';

const pinataJWT = "YOUR_JWT_KEY";

function List() {
  const [selectedFile, setSelectedFile] = useState(null);
  const [cid, setCid] = useState(null);

  const changeHandler = (event) => {
    setSelectedFile(event.target.files[0]);
  };

  const handleSubmission = async () => {
    try {
      const formData = new FormData();
      formData.append("file", selectedFile);
      const metadata = JSON.stringify({
        name: "File name",
      });
      formData.append("pinataMetadata", metadata);

      const options = JSON.stringify({
        cidVersion: 0,
      });
      formData.append("pinataOptions", options);

      const res = await fetch(
        "https://api.pinata.cloud/pinning/pinFileToIPFS",
        {
          method: "POST",
          headers: {
            Authorization: `Bearer ${pinataJWT}`,
          },
          body: formData,
        }
      );
      const resData = await res.json();
      setCid(resData.IpfsHash);
      console.log(resData);
    } catch (error) {
      console.log(error);
    }
  };

  return (
    <>
      <label className="form-label"> Choose your image file to upload on the decentralised storage</label>
      <input type="file" onChange={changeHandler} />
      <button onClick={handleSubmission}>Submit</button>
      {cid && (
        <>
        <div className="image-card">
        <img
          src={`https://gateway.pinata.cloud/ipfs/${cid}`}
          alt="ipfs image"
        />
        </div>
        <h2 className="text-white">Your image is uploaded successfully. Here is your CID of uploaded image.</h2>
        <TextDisplayBox text={cid} />
        </>
      )}
    </>
  );
}

export default List;

Get API Key

In this project, we will use the 'Pinata' as an IPFS service provider. Sign up on the pinata and from the dashboard create a new API key with admin access. Here you will get the 'API Key', 'API Secret', and 'JWT'. Replace the 'YOUR_JWT_KEY' with your JWT value. Now in the 'src' directory create a new CSS file named 'List.css' and paste the following code on this file.

.container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background-color: #100c08; /* Smoky background */
  }
  
  .form-label {
    margin-bottom: 10px;
    color: white;
    font-size: 32px;
  }
  
  input[type="file"] {
    margin-bottom: 10px;
    font-size:18px;
    color:white;
    border-radius:5px;
    border: solid 1px white;
  }
  
  button {
    padding: 10px 20px;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size:18px;
  }
  
  button:hover {
    background-color: #0056b3;
  }
  
  .image-card {
    margin-top: 28px;
    width: 400px;
    height: 400px;
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 0 10px rgba(0, 123, 255, 0.5); /* Glow effect */
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s;
  }
  
  
  .image-card:hover .image {
    transform: scale(1.05); /* Scale up on hover */
  }
  
  .text-white{
      color: white;
  }

Have you noticed that we have used a component named 'TextDisplayBox' for displaying the CID? Let's create this component in the 'src' directory as 'TextDisplayBox.js' and paste the following code into that file.

import React, { useState } from 'react';
import './TextDisplayBox.css'; 

const TextDisplayBox = ({ text }) => {
  const [copied, setCopied] = useState(false);

  // Function to handle copying text to clipboard
  const copyToClipboard = () => {
    navigator.clipboard.writeText(text);
    setCopied(true);
    // Reset copied state after 2 seconds
    setTimeout(() => {
      setCopied(false);
    }, 2000);
  };

  return (
    <div className="text-display-box">
      {/* Show the text inside the box */}
      <div className="text">{text}</div>
      
      {/* Show copy button */}
      <button className="copy-button" onClick={copyToClipboard}>
        {copied ? 'Copied!' : 'Copy'}
      </button>
    </div>
  );
};

export default TextDisplayBox;

Now create a CSS file named 'TextDisplayBox.css' to beautify the component and paste the following code into that file.

.text-display-box {
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 10px;
    margin-bottom: 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top:16px;
    color:white;
  }
  
  .text {
    flex-grow: 1;
  }
  
  .copy-button {
    padding: 5px 10px;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 3px;
    cursor: pointer;
  }
  
  .copy-button:hover {
    background-color: #0056b3;
  }
  

We have done with the component creation part now import and include these components into our existing 'index.js' file, to achieve this update this file's code with the following code.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import List from './List';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>

    <div className="container">
      <List />
    </div>

  </React.StrictMode>
);

reportWebVitals();

Run the application

Now our application is ready to run, so start the application by running the following command into the terminal.

npm start

Output

npm-start

It shows that the application is now running on the 'http://localhost:3001/' in your case it may be 'http://localhost:3000/', anyway navigate to this URL and you will see the output as follows.

app-output

Now click on the choose file input box select the image that you want to upload and hit the submit button. After a few seconds, you will see the output as follows.

image-output

It will display the uploaded image file and the CID of that file you can copy this also. This is the basic level of demonstration of the integration of IPFS with the react application feel free to customize this according to your requirements.

Conclusion

With the combination of IPFS and React, developers can build decentralized and resilient web applications that offer improved performance and security. As you continue to explore and customize this integration, you'll discover endless possibilities for creating innovative web experiences in the decentralized web era.

FAQ's

Q. What is IPFS?

A. IPFS, short for InterPlanetary File System, is a decentralized protocol for storing and accessing files on the web. It breaks files into smaller chunks and distributes them across a network of interconnected nodes, making data retrieval faster and more secure.

Q. How does IPFS work?

A. IPFS uses content addressing to uniquely identify files based on their content, rather than their location. When a file is added to IPFS, it's broken into smaller chunks, hashed, and distributed across multiple nodes. This allows files to be retrieved from any node on the network, improving redundancy and availability.

Q. What is Pinata?

A. Pinata is a service that provides IPFS hosting and management tools. It allows developers to easily store and manage files on the IPFS network, providing features like file pinning, metadata management, and content delivery.

Q. Is IPFS suitable for all types of applications?

A. While IPFS offers many benefits, it may not be suitable for all types of applications. Applications that require real-time data updates or high throughput may face challenges with IPFS due to its distributed nature. However, for applications that prioritize decentralized storage and data integrity, IPFS can be a valuable tool.


Similar Articles