{"id":2150,"date":"2022-02-08T08:28:01","date_gmt":"2022-02-08T14:28:01","guid":{"rendered":"https:\/\/www.becomebetterprogrammer.com\/?p=2150"},"modified":"2022-04-25T09:33:04","modified_gmt":"2022-04-25T14:33:04","slug":"upload-files-using-react-ipfs-infura","status":"publish","type":"post","link":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/","title":{"rendered":"How to Upload Files using React and IPFS with Infura"},"content":{"rendered":"\n<p>With web3 gaining more and more popularity, looking for ways to integrate solutions to make the web decentralized becomes critical in the process of moving forward from the deficiencies we see when using centralized solutions, such as saving files in specific service provider cloud solutions. In this article, you will learn a different way to save files in the web using IPFS, a peer-to-peer (p2p) storage network.<\/p>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#What_is_IPFS\" >What is IPFS?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Why_does_IPFS_matters\" >Why does IPFS matters?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#How_to_Create_a_React_App_to_Upload_Files_using_IPFS_and_Infura\" >How to Create a React App to Upload Files using IPFS and Infura<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Starting_the_Project\" >Starting the Project<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Install_dependencies\" >Install dependencies<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Detecting_IPFS_Client\" >Detecting IPFS Client<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Wiring_up_form_to_upload_files\" >Wiring up form to upload files<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Displaying_files_uploaded\" >Displaying files uploaded<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Run_the_code\" >Run the code<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Remove_duplicate_images\" >Remove duplicate images<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Adding_your_IPFS_Infura_project\" >Adding your IPFS Infura project<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Full_Code\" >Full Code<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Interesting_in_Web3_Development\" >Interesting in Web3 Development?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/upload-files-using-react-ipfs-infura\/#Conclusion\" >Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\" id=\"what-is-ipfs\"><span class=\"ez-toc-section\" id=\"What_is_IPFS\"><\/span>What is IPFS?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p><a href=\"https:\/\/docs.ipfs.io\/concepts\/what-is-ipfs\/\" target=\"_blank\" rel=\"noreferrer noopener\">According to the official documentation<\/a>, <strong>IPFS (InterPlanetary File System<\/strong>)<strong> is a distributed system for storing and accessing files, websites, applications, and data<\/strong>. This means the data is not stored in a  centralized location, but rather in multiple nodes of the network.<\/p>\n\n\n\n<p>With typical cloud storage, you upload data and you get a link, URL, or a way to locate where the data is. This is a location identifier. On the other hand, <strong>IPFS uses a content identifier (CID).<\/strong><\/p>\n\n\n\n<p>This means, every time we upload data using IPFS, IPFS uses a cryptographic hash to generate a CID. This CID is unique as it is strictly based on the content of data or files. For instance, if by mistake you uploaded the incorrect file, and want to upload a new file, what happens with IPFS is you are uploading a new file, creating a new version of the previous file. This is different from overriding an existing file, and completing losing the content of old version of the file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"why-does-ipfs-matters\"><span class=\"ez-toc-section\" id=\"Why_does_IPFS_matters\"><\/span>Why does IPFS matters?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>IPFS will play a key role in the development of Web3 applications. For instance, it is critical to use the least amount of space when developing smart contracts. Especially due to how expensive they can be to deploy them.<\/p>\n\n\n\n<p>Now, if you think about the amount of space it would take for storing files or images in a smart contract, that would be very expensive.<\/p>\n\n\n\n<p>Those who think of using AWS S3 or any similar platform to store those files and pass the file keys into the smart contract might be a solution, but it defeats the purpose of Web3.<\/p>\n\n\n\n<p>Web3 aims to be decentralized, and using services such as AWS S3 is quite the opposite of being decentralized as all the data is stored in a specific AWS region. On the other hand, when using IPFS, pieces of data are stored in different locations, or in different nodes in the network.<\/p>\n\n\n\n<p>This allows two things:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Users gain control back of their data, instead of being dependent on service providers<\/li><li>Faster retrieval times as the data is stored in multiple nodes, hence, retrieving each piece of information form several places, perfect for distributing high volumes of data<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"starting-the-project\"><span class=\"ez-toc-section\" id=\"How_to_Create_a_React_App_to_Upload_Files_using_IPFS_and_Infura\"><\/span>How to Create a React App to Upload Files using IPFS and Infura<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"starting-the-project\"><span class=\"ez-toc-section\" id=\"Starting_the_Project\"><\/span>Starting the Project<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Let&#8217;s create the React project using the CLI. This project will use the TypeScript template.<\/p>\n\n\n\n<pre class=\"wp-block-code language-bash\"><code>npx create-react-app react-ipfs-typescript --template typescript<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"install-dependencies\"><span class=\"ez-toc-section\" id=\"Install_dependencies\"><\/span>Install dependencies<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>We will only use one dependency to upload files using IPFS, which is <code>ipfs-http-client<\/code>. For this project, we use <code>npm<\/code>, but feel free to add the dependency using <code>yarn<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-bash\"><code>npm install --save ipfs-http-client<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"detecting-ipfs-client\"><span class=\"ez-toc-section\" id=\"Detecting_IPFS_Client\"><\/span>Detecting IPFS Client<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Open the <em>App.tsx<\/em> file and import the <code>ipfs-http-client<\/code> to the file. We will use the <a href=\"https:\/\/github.com\/ipfs\/js-ipfs\/blob\/master\/packages\/ipfs-http-client\/README.md#createoptions\" target=\"_blank\" rel=\"noreferrer noopener\"><code>create<\/code><\/a> function provided by <code>ipfs-http-client<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>import { create, CID, IPFSHTTPClient } from \"ipfs-http-client\";<\/code><\/pre>\n\n\n\n<p>Inside the <code>App<\/code> component, create a variable called <code>ipfs<\/code>. This will store the IPFS HTTP Client, which is returned using <code>create<\/code> function, unless there are errors establishing the connection.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>let ipfs: IPFSHTTPClient | undefined;\n  try {\n    ipfs = create({\n      url: \"https:\/\/ipfs.infura.io:5001\/api\/v0\",\n\n    });\n  } catch (error) {\n    console.error(\"IPFS error \", error);\n    ipfs = undefined;\n  }<\/code><\/pre>\n\n\n\n<p>This is important to do as if there we don&#8217;t have the IPFS HTTP Client, it is not going to be possible to upload the files from our app.<\/p>\n\n\n\n<p>in here <a href=\"https:\/\/github.com\/ipfs\/js-ipfs\/blob\/master\/docs\/BROWSERS.md#limitations-of-the-browser-context\" target=\"_blank\" rel=\"noopener\">are current limitations when using IPFS in the browser<\/a>. One of them is, Web APIs require or are restricted by Secure Context policies. In other words, IPFS needs to run either in HTTPS or localhost. We shouldn&#8217;t have any problems with this as we are going to leverage IPFS Infura, which runs in HTTPS.<\/p>\n\n\n\n<p>Update the template to verify if there has been established a connection with IPFS. If <code>ipfs<\/code> is <code>undefined<\/code> display a user-friendly message.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>return (\n    &lt;div className=\"App\"&gt;\n      &lt;header className=\"App-header\"&gt;\n        {!ipfs &amp;&amp; (\n          &lt;p&gt;Oh oh, Not connected to IPFS. Checkout out the logs for errors&lt;\/p&gt;\n        )}\n      &lt;\/header&gt;\n    &lt;\/div&gt;\n  );<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"wiring-up-form-to-upload-files\"><span class=\"ez-toc-section\" id=\"Wiring_up_form_to_upload_files\"><\/span>Wiring up form to upload files<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>On the other hand, if we detect <code>ipfs<\/code> has an instance of <code>IPFSHTTPClient<\/code> that means we have successfully established a connection with IPFS. Hence, we can generate a simple form to upload files.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>{ipfs &amp;&amp; (\n          &lt;&gt;\n            &lt;p&gt;Upload File using IPFS&lt;\/p&gt;\n\n            &lt;form onSubmit={onSubmitHandler}&gt;\n              &lt;input name=\"file\" type=\"file\" \/&gt;\n\n              &lt;button type=\"submit\"&gt;Upload File&lt;\/button&gt;\n            &lt;\/form&gt;\n          &lt;\/&gt;\n        )}<\/code><\/pre>\n\n\n\n<p>Notice this form depends on <code>onSubmitHandler<\/code> function, or an event handler to upload any files selected by the user. Also, the <code>onSubmitHandler<\/code> will be in charge of updating the list of files uploaded. Hence, we will use <code>React.useState<\/code> to keep track of the files.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>\/\/ add this at the beginning of the App component\nconst &#91;images, setImages] = React.useState&lt;{ cid: CID; path: string }&#91;]&gt;(&#91;]);<\/code><\/pre>\n\n\n\n<p>Then, add the <code>onSubmitHandler<\/code> function inside the <code>App<\/code> component.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>  \/**\n   * @description event handler that uploads the file selected by the user\n   *\/\n  const onSubmitHandler = async (event: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {\n    event.preventDefault();\n    const form = event.target as HTMLFormElement;\n    const files = (form&#91;0] as HTMLInputElement).files;\n\n    if (!files || files.length === 0) {\n      return alert(\"No files selected\");\n    }\n\n    const file = files&#91;0];\n    \/\/ upload files\n    const result = await (ipfs as IPFSHTTPClient).add(file);\n\n    setImages(&#91;\n      ...images,\n      {\n        cid: result.cid,\n        path: result.path,\n      },\n    ]);\n\n    form.reset();\n  };<\/code><\/pre>\n\n\n\n<p>The logic should be straightforward. However, this is what is going on:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Verify a file was selected. Otherwise, notify the user no files have been selected.<\/li><li>Use the <code>ipfs.add<\/code> method to upload file into IPFS.<\/li><li>The <code>add<\/code> method returns a result of type <code>AddResult<\/code>, which contains the following properties <code>cid<\/code>, <code>mode<\/code>, <code>mtime<\/code>, <code>path<\/code>, and <code>size<\/code>. The most important properties is the <code>cid<\/code> as it is the unique identifier given to the file uploaded. We store the <code>cid<\/code> and the <code>path<\/code>. We will use the <code>path<\/code> to display image files in the app.<\/li><li>Update the state of the images by adding the latest file uploaded into IPFS to the array of <code>images<\/code>.<\/li><\/ol>\n\n\n\n<p><strong>Note 1:<\/strong> The <code>ipfs.add<\/code> method is not only capable of uploading files into IPFS, but also data. Feel free to upload any random text to IPFS, such as <code>await (ipfs as IPFSHTTPClient).add('Hello World')<\/code>.<\/p>\n\n\n\n<p><strong>Note 2:<\/strong> This tutorial is basic, hence it doesn&#8217;t enforce other checks such as checking the file type, size, or mime type prior uploading the file. It is recommended to do so based on the requirements of your project.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"displaying-files-uploaded\"><span class=\"ez-toc-section\" id=\"Displaying_files_uploaded\"><\/span>Displaying files uploaded<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Currently, we have the logic wired up to upload files, and even update the array of files uploaded. However, we are not displaying the files uploaded in the app. Let&#8217;s update the template to also display the files. <\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>{ipfs &amp;&amp; (\n          &lt;&gt;\n            &lt;p&gt;Upload File using IPFS&lt;\/p&gt;\n\n            &lt;form onSubmit={onSubmitHandler}&gt;\n              &lt;input name=\"file\" type=\"file\" \/&gt;\n\n              &lt;button type=\"submit\"&gt;Upload File&lt;\/button&gt;\n            &lt;\/form&gt;\n\n            &lt;div&gt;\n              {images.map((image, index) =&gt; (\n                &lt;img\n                  alt={`Uploaded #${index + 1}`}\n                  src={\"https:\/\/ipfs.infura.io\/ipfs\/\" + image.path}\n                  style={{ maxWidth: \"400px\", margin: \"15px\" }}\n                  key={image.cid.toString() + index}\n                \/&gt;\n              ))}\n            &lt;\/div&gt;\n          &lt;\/&gt;\n        )}<\/code><\/pre>\n\n\n\n<p>We <em>assumed<\/em> all of the files are images. Therefore, we use <code>map<\/code> method to iterate through all of the images uploaded and return an <code>img<\/code> HTML tag using the path <code>\"https:\/\/ipfs.infura.io\/ipfs\/\" + image.path<\/code>, to set up the <code>src<\/code> attribute. Consider improving the <code>alt<\/code> and <code>style<\/code> attribute to better fit your project needs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"run-the-code\"><span class=\"ez-toc-section\" id=\"Run_the_code\"><\/span>Run the code<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Run the app using the <code>start<\/code> script in the terminal.<\/p>\n\n\n\n<pre class=\"wp-block-code language-bash\"><code>npm run start<\/code><\/pre>\n\n\n\n<p>It should automatically open the application in <em>localhost:3000<\/em>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"775\" height=\"512\" src=\"https:\/\/www.becomebetterprogrammer.com\/wp-content\/uploads\/2022\/02\/Default-view-of-the-app.png\" alt=\"\" class=\"wp-image-2151\" title=\"Default view of the app\" srcset=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Default-view-of-the-app.png 775w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Default-view-of-the-app-300x198.png 300w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Default-view-of-the-app-768x507.png 768w\" sizes=\"auto, (max-width: 775px) 100vw, 775px\" \/><figcaption>The default view of the app<\/figcaption><\/figure><\/div>\n\n\n\n<p>Choose a file and click the <em>Upload File<\/em> button. If there are no errors, the file will successfully be uploaded and rendered in the app. Also, the form should reset.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"980\" height=\"790\" src=\"https:\/\/www.becomebetterprogrammer.com\/wp-content\/uploads\/2022\/02\/App-view-after-uploading-a-few-files-into-IPFS.png\" alt=\"\" class=\"wp-image-2152\" title=\"App view after uploading a few files into IPFS\" srcset=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/App-view-after-uploading-a-few-files-into-IPFS.png 980w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/App-view-after-uploading-a-few-files-into-IPFS-300x242.png 300w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/App-view-after-uploading-a-few-files-into-IPFS-768x619.png 768w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\" \/><figcaption>App view after uploading a few files into IPFS<\/figcaption><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"remove-duplicate-images\"><span class=\"ez-toc-section\" id=\"Remove_duplicate_images\"><\/span>Remove duplicate images<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>If you noticed in the previous image, we uploaded the same image twice. Remember, each file gets a CID and a path as a result of using the <code>ipfs.add<\/code> method.<\/p>\n\n\n\n<p>Add a temporary log to get information of the images uploaded.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>const onSubmitHandler = async (event: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {\n     \/\/ onSubmitHandler logic\n};\n\n\/\/ add temporary log\nconsole.log('images ', images);<\/code><\/pre>\n\n\n\n<p>Then, use the application an upload the same image multiple times. Keep the console of the developer tools open to inspect the logs of the images.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"164\" src=\"https:\/\/www.becomebetterprogrammer.com\/wp-content\/uploads\/2022\/02\/Images-with-the-same-path.png\" alt=\"\" class=\"wp-image-2154\" title=\"Images with the same path\" srcset=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Images-with-the-same-path.png 626w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Images-with-the-same-path-300x79.png 300w\" sizes=\"auto, (max-width: 626px) 100vw, 626px\" \/><figcaption>Images with the same path<\/figcaption><\/figure><\/div>\n\n\n\n<p>Notice the same path and even the CID is generated for those images we uploaded multiple times. The reason is because the CID stands for content identifier. The CID is generated based on the content itself using a cryptographic hash, which by default IPFS uses SH2-256. Therefore, everytime the same file is uploaded, the same CID is generated.<\/p>\n\n\n\n<p>Ideally, we would remove the duplicates by inspecting the CID. However, the CID is an object containing the properties <code>hash<\/code>, <code>code<\/code>, <code>multihash<\/code>, <code>version<\/code>, and more if you inspect one of the images. Instead, we will filter out duplicate images by comparing the path of the image. <\/p>\n\n\n\n<p>Update the <code>onSubmitHandler<\/code> logic with the following, which uses a Set to easily get the unique paths, hence, unique images. Then, based on the unique paths, get the unique image object structure, which contains the properties <code>cid<\/code> and <code>path<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>\/**\n   * @description event handler that uploads the file selected by the user\n   *\/\n  const onSubmitHandler = async (event: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {\n    event.preventDefault();\n    const form = event.target as HTMLFormElement;\n    const files = (form&#91;0] as HTMLInputElement).files;\n\n    if (!files || files.length === 0) {\n      return alert(\"No files selected\");\n    }\n\n    const file = files&#91;0];\n    \/\/ upload files\n    const result = await (ipfs as IPFSHTTPClient).add(file);\n\n    const uniquePaths = new Set(&#91;\n      ...images.map((image) =&gt; image.path),\n      result.path,\n    ]);\n    const uniqueImages = &#91;...uniquePaths.values()]\n      .map((path) =&gt; {\n        return &#91;\n          ...images,\n          {\n            cid: result.cid,\n            path: result.path,\n          },\n        ].find((image) =&gt; image.path === path);\n      });\n    \n      \/\/ @ts-ignore\n    setImages(uniqueImages);\n\n    form.reset();\n  };<\/code><\/pre>\n\n\n\n<p>Go ahead and test this out. You should only see unique images displayed in the app after every time you upload a new image.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"796\" height=\"640\" src=\"https:\/\/www.becomebetterprogrammer.com\/wp-content\/uploads\/2022\/02\/Unique-images-displayed-in-the-app.png\" alt=\"\" class=\"wp-image-2155\" title=\"Unique images displayed in the app\" srcset=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Unique-images-displayed-in-the-app.png 796w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Unique-images-displayed-in-the-app-300x241.png 300w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Unique-images-displayed-in-the-app-768x617.png 768w\" sizes=\"auto, (max-width: 796px) 100vw, 796px\" \/><figcaption>Unique images displayed in the app<\/figcaption><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"adding-your-ipfs-infura-project\"><span class=\"ez-toc-section\" id=\"Adding_your_IPFS_Infura_project\"><\/span>Adding your IPFS Infura project <span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>If you are interested in creating your own IPFS Infura project, <a href=\"https:\/\/infura.io\/register\" target=\"_blank\" rel=\"noreferrer noopener\">register for an Infura account<\/a> and set up the project.<\/p>\n\n\n\n<p><strong>Note:<\/strong> While doing so, they will require a credit card to create an IPFS Infura project. At the moment of writing this tutorial, you get up to 5GB of free storage prior Infura starts charging for storage.<\/p>\n\n\n\n<p><strong>Note 2<\/strong>: You can always remove the IPFS Infura project after a while, or even after finishing this tutorial to avoid any unexpected charges if for some reason you lose your project secret keys.<\/p>\n\n\n\n<p>Go to the settings page of your IPFS project. You should see the project ID and project secret. Copy these values and don&#8217;t share it with anyone. We show you the values for the purposes of this tutorial.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"409\" src=\"https:\/\/www.becomebetterprogrammer.com\/wp-content\/uploads\/2022\/02\/IPFS-Infura-Settings-1024x409.png\" alt=\"\" class=\"wp-image-2156\" title=\"IPFS Infura Settings\" srcset=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/IPFS-Infura-Settings-1024x409.png 1024w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/IPFS-Infura-Settings-300x120.png 300w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/IPFS-Infura-Settings-768x307.png 768w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/IPFS-Infura-Settings-1536x613.png 1536w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/IPFS-Infura-Settings.png 1595w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>IPFS Infura Settings<\/figcaption><\/figure><\/div>\n\n\n\n<p>Go back to the <em>App.tsx<\/em> file, and add the constants above the <code>App<\/code> component to store the keys. We will use them to generate the authorization key by generating a base64 of the keys using the function <code>btoa<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>const projectId = \"&lt;YOUR PROJECT ID&gt;\";\nconst projectSecret = \"&lt;YOUR PROJECT SECRET&gt;\";\nconst authorization = \"Basic \" + btoa(projectId + \":\" + projectSecret);<\/code><\/pre>\n\n\n\n<p><strong>Note<\/strong>: Feel free to use environment variables for a safer alternative.<\/p>\n\n\n\n<p>Now, we are going to update the argument passed in the <code>create<\/code> function to include the <code>authorization<\/code> in the headers.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>let ipfs: IPFSHTTPClient | undefined;\n  try {\n    ipfs = create({\n      url: \"https:\/\/ipfs.infura.io:5001\/api\/v0\",\n      headers: {\n        authorization,\n      },\n    });\n  } catch (error) {\n    console.error(\"IPFS error \", error);\n    ipfs = undefined;\n  }<\/code><\/pre>\n\n\n\n<p>Test the app one more time, and upload a few files.<\/p>\n\n\n\n<p>You should see the paths of the images uploaded in your IPFS Infura project.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"300\" src=\"https:\/\/www.becomebetterprogrammer.com\/wp-content\/uploads\/2022\/02\/Paths-of-images-uploaded-in-the-IPFS-Infura-project-dashboard-1024x300.png\" alt=\"\" class=\"wp-image-2157\" title=\"Paths of images uploaded in the IPFS Infura project dashboard\" srcset=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Paths-of-images-uploaded-in-the-IPFS-Infura-project-dashboard-1024x300.png 1024w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Paths-of-images-uploaded-in-the-IPFS-Infura-project-dashboard-300x88.png 300w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Paths-of-images-uploaded-in-the-IPFS-Infura-project-dashboard-768x225.png 768w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Paths-of-images-uploaded-in-the-IPFS-Infura-project-dashboard-1536x450.png 1536w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/02\/Paths-of-images-uploaded-in-the-IPFS-Infura-project-dashboard.png 1764w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Paths of images uploaded in the IPFS Infura project dashboard<\/figcaption><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"full-code\"><span class=\"ez-toc-section\" id=\"Full_Code\"><\/span>Full Code<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Here is the full code or feel free to checkout the full version of the code in <a href=\"https:\/\/github.com\/arealesramirez\/react-ipfs-typescript\" target=\"_blank\" rel=\"noreferrer noopener\">this repository<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-typescript\"><code>import React from \"react\";\nimport \".\/App.css\";\nimport { create, CID, IPFSHTTPClient } from \"ipfs-http-client\";\n\nconst projectId = '&lt;YOUR PROJECT ID&gt;';\nconst projectSecret = '&lt;YOUR PROJECT SECRET&gt;';\nconst authorization = \"Basic \" + btoa(projectId + \":\" + projectSecret);\n\nfunction App() {\n  const &#91;images, setImages] = React.useState&lt;{ cid: CID; path: string }&#91;]&gt;(&#91;]);\n\n  let ipfs: IPFSHTTPClient | undefined;\n  try {\n    ipfs = create({\n      url: \"https:\/\/ipfs.infura.io:5001\/api\/v0\",\n      headers: {\n        authorization,\n      },\n    });\n  } catch (error) {\n    console.error(\"IPFS error \", error);\n    ipfs = undefined;\n  }\n\n  \/**\n   * @description event handler that uploads the file selected by the user\n   *\/\n  const onSubmitHandler = async (event: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {\n    event.preventDefault();\n    const form = event.target as HTMLFormElement;\n    const files = (form&#91;0] as HTMLInputElement).files;\n\n    if (!files || files.length === 0) {\n      return alert(\"No files selected\");\n    }\n\n    const file = files&#91;0];\n    \/\/ upload files\n    const result = await (ipfs as IPFSHTTPClient).add(file);\n\n    const uniquePaths = new Set(&#91;\n      ...images.map((image) =&gt; image.path),\n      result.path,\n    ]);\n    const uniqueImages = &#91;...uniquePaths.values()]\n      .map((path) =&gt; {\n        return &#91;\n          ...images,\n          {\n            cid: result.cid,\n            path: result.path,\n          },\n        ].find((image) =&gt; image.path === path);\n      });\n    \n      \/\/ @ts-ignore\n    setImages(uniqueImages);\n\n    form.reset();\n  };\n\n  console.log(\"images \", images);\n\n  return (\n    &lt;div className=\"App\"&gt;\n      &lt;header className=\"App-header\"&gt;\n        {ipfs &amp;&amp; (\n          &lt;&gt;\n            &lt;p&gt;Upload File using IPFS&lt;\/p&gt;\n\n            &lt;form onSubmit={onSubmitHandler}&gt;\n              &lt;input name=\"file\" type=\"file\" \/&gt;\n\n              &lt;button type=\"submit\"&gt;Upload File&lt;\/button&gt;\n            &lt;\/form&gt;\n\n            &lt;div&gt;\n              {images.map((image, index) =&gt; (\n                &lt;img\n                  alt={`Uploaded #${index + 1}`}\n                  src={\"https:\/\/ipfs.infura.io\/ipfs\/\" + image.path}\n                  style={{ maxWidth: \"400px\", margin: \"15px\" }}\n                  key={image.cid.toString() + index}\n                \/&gt;\n              ))}\n            &lt;\/div&gt;\n          &lt;\/&gt;\n        )}\n\n        {!ipfs &amp;&amp; (\n          &lt;p&gt;Oh oh, Not connected to IPFS. Checkout out the logs for errors&lt;\/p&gt;\n        )}\n      &lt;\/header&gt;\n    &lt;\/div&gt;\n  );\n}\n\nexport default App;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"interesting-in-web3-development\"><span class=\"ez-toc-section\" id=\"Interesting_in_Web3_Development\"><\/span>Interesting in Web3 Development?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>I&#8217;ve written other web3 related articles I thought you will find interesting, feel free to check them out.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/www.becomebetterprogrammer.com\/create-solana-smart-contract\/\">Guide: How to Create a Solana Program or \u201cSmart Contract\u201d<\/a><\/li><li><a href=\"https:\/\/www.becomebetterprogrammer.com\/web3-react-connect-to-phantom\/\">How to Connect a Web3 React App to Phantom using TypeScript<\/a><\/li><\/ul>\n\n\n\n<p>There is also more content related to TypeScript and JavaScript, and programming in general for those interested in finding new sources of information.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"conclusion\"><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>In this tutorial you learned how to upload files using IPFS using React and TypeScript. Despite IPFS innovative concept of being a decentralized solution to store files using a peer-to-peer storage network, it is fairly simple to use it with traditional applications. While this tutorial was focused on uploading files using IPFS and React, it is possible to use the same fundamentals and apply them using different frontend frameworks or even plain vanilla JavaScript.<\/p>\n\n\n\n<p><strong>Was this article helpful?<\/strong><\/p>\n\n\n\n<p>Share your thoughts by replying on Twitter of <a href=\"https:\/\/twitter.com\/bbprogrammer\" target=\"_blank\" rel=\"noreferrer noopener\">Become A Better Programmer<\/a> or to <a href=\"https:\/\/twitter.com\/arealesramirez\" target=\"_blank\" rel=\"noreferrer noopener\">personal my Twitter account<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"twitter-tweet\" data-width=\"550\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">What is IPFS?<br><br>In short: it is a decentralized way to store and access data.<br><br>Every <a href=\"https:\/\/twitter.com\/hashtag\/web3?src=hash&amp;ref_src=twsrc%5Etfw\" target=\"_blank\" rel=\"noopener\">#web3<\/a> <a href=\"https:\/\/twitter.com\/hashtag\/developer?src=hash&amp;ref_src=twsrc%5Etfw\" target=\"_blank\" rel=\"noopener\">#developer<\/a> should care about this in aims to find new ways to upload files as it is expensive to pay for space developing smart contracts.<br><br>&#8230;and we wrote about it<a href=\"https:\/\/t.co\/nUmiK46Qrb\">https:\/\/t.co\/nUmiK46Qrb<\/a><\/p>&mdash; Become A Better Programmer (@bbprogrammer) <a href=\"https:\/\/twitter.com\/bbprogrammer\/status\/1491058196957433857?ref_src=twsrc%5Etfw\" target=\"_blank\" rel=\"noopener\">February 8, 2022<\/a><\/blockquote><script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Web3 decentralized has come to stay, and IPFS is a way to make storage decentralized. Learn how to upload files using IPFS Infura is a simple React app.<\/p>\n","protected":false},"author":1,"featured_media":2162,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[19,29],"tags":[],"class_list":["post-2150","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-typescript","category-web3","generate-columns","tablet-grid-50","mobile-grid-100","grid-parent","grid-50"],"_links":{"self":[{"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/posts\/2150","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/comments?post=2150"}],"version-history":[{"count":5,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/posts\/2150\/revisions"}],"predecessor-version":[{"id":2456,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/posts\/2150\/revisions\/2456"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/media\/2162"}],"wp:attachment":[{"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/media?parent=2150"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/categories?post=2150"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/tags?post=2150"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}