Merge pull request #304 from oceanprotocol/feature/react
Rewrite react tutorials
Before Width: | Height: | Size: 456 KiB After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 399 KiB After Width: | Height: | Size: 216 KiB |
Before Width: | Height: | Size: 420 KiB After Width: | Height: | Size: 213 KiB |
Before Width: | Height: | Size: 553 KiB After Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 302 KiB |
BIN
content/tutorials/images/react-app-06.png
Normal file
After Width: | Height: | Size: 244 KiB |
@ -10,168 +10,56 @@ This is a continuation of the React App Tutorial. Make sure you already did the
|
|||||||
1. [React App Setup](/tutorials/react-setup/)
|
1. [React App Setup](/tutorials/react-setup/)
|
||||||
2. [Publish a Data Set](/tutorials/react-publish-data-set/)
|
2. [Publish a Data Set](/tutorials/react-publish-data-set/)
|
||||||
|
|
||||||
Open `src/App.js` from your `marketplace/` folder.
|
Open `src/index.js` from your `marketplace/` folder.
|
||||||
|
|
||||||
## Retrieve Assets
|
## Search Assets
|
||||||
|
|
||||||
In the previous tutorial we added asset publishing. We can now search for published assets for consumption. Just after the `submitAsset()` function we can add a new function that will handle search:
|
In the previous tutorial we added asset publishing. We can now search for published assets for consumption.
|
||||||
|
|
||||||
```js:title=src/App.js
|
We will store the search results in the local component state so we have to set its initial state first:
|
||||||
// ...
|
|
||||||
async retrieveAssets() {
|
|
||||||
this.search = await this.ocean.assets.search('10 Monkey Species Small')
|
|
||||||
console.log(this.search)
|
|
||||||
alert(
|
|
||||||
'Asset successfully retrieved. Look into your console to see the search response.'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
Now we need a button to start our search inside the render function just after the _Register asset_ button:
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 15-18 GITHUB-EMBED
|
||||||
|
|
||||||
```jsx:title=src/App.js
|
Just after the `registerAsset()` function we add a new `searchAssets` function that will handle search:
|
||||||
// ...
|
|
||||||
<button onClick={() => this.retrieveAssets()}>Retrieve assets</button>
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Consume Assets
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 54-67 GITHUB-EMBED
|
||||||
|
|
||||||
|
Now we need a button to start our search inside the `render()` function, just after the _Register asset_ button:
|
||||||
|
|
||||||
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 114-115 GITHUB-EMBED
|
||||||
|
|
||||||
|
## Consume Asset
|
||||||
|
|
||||||
Consuming means downloading one or multiple files attached to an asset. During that process the initial `url` value we added during the publish process for each file will be decrpyted and the file can be downloaded.
|
Consuming means downloading one or multiple files attached to an asset. During that process the initial `url` value we added during the publish process for each file will be decrpyted and the file can be downloaded.
|
||||||
|
|
||||||
With the following code we start the consume process with the first search result, then go on to download its first attached file. Put it after the `retrieveAssets()` function:
|
With the following code we start the consume process with the first search result, then go on to download its first attached file. Put it after the `searchAssets()` function:
|
||||||
|
|
||||||
```js:title=src/App.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 69-95 GITHUB-EMBED
|
||||||
// ...
|
|
||||||
async consumeAsset() {
|
|
||||||
// get all accounts
|
|
||||||
const accounts = await this.ocean.accounts.list()
|
|
||||||
// get first asset
|
|
||||||
const consumeAsset = this.search.results[0]
|
|
||||||
// get service we want to execute
|
|
||||||
const service = consumeAsset.findServiceByType('Access')
|
|
||||||
// order service agreement
|
|
||||||
const agreement = await this.ocean.assets.order(
|
|
||||||
consumeAsset.id,
|
|
||||||
service.serviceDefinitionId,
|
|
||||||
accounts[0]
|
|
||||||
)
|
|
||||||
// consume it
|
|
||||||
await this.ocean.assets.consume(
|
|
||||||
agreement,
|
|
||||||
consumeAsset.id,
|
|
||||||
service.serviceDefinitionId,
|
|
||||||
accounts[0],
|
|
||||||
'',
|
|
||||||
0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
We still need a button to start consumption. In the render function, just after the _Retrieve assets_ button, add:
|
We still need a button to start consumption. In the render function, just after the _Search assets_ button, add:
|
||||||
|
|
||||||
```jsx:title=src/App.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 116-118 GITHUB-EMBED
|
||||||
// ...
|
|
||||||
<button onClick={() => this.consumeAsset()}>Consume asset</button>
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
With all these buttons in place, you should see this:
|
With all these buttons in place, you should see this:
|
||||||
|
|
||||||
![React App 05](images/react-app-05.png)
|
![React app with all actions in place](images/react-app-06.png)
|
||||||
|
|
||||||
> Tip: Before clicking the `Retrieve assets` button, it might help to reload the page.
|
Go ahead and click the _Search assets_ button, and then the _Consume asset_ button. Approve all the MetaMask dialog boxes.
|
||||||
|
|
||||||
Go ahead and click the _Retrieve assets_ button, and then the _Consume asset_ button. Approve all the MetaMask dialog boxes.
|
|
||||||
|
|
||||||
Have a look into `console.log` to see the various steps of the search and consume process. If you have no errors in your `console.log` and can see your asset files listed, you have a working marketplace.
|
Have a look into `console.log` to see the various steps of the search and consume process. If you have no errors in your `console.log` and can see your asset files listed, you have a working marketplace.
|
||||||
|
|
||||||
> Consuming an asset will throw an error `Requested did is not found in the keeper network`. We are currently [investigating why that is happening](https://github.com/oceanprotocol/barge/issues/144) in either squid-js or Brizo and will remove this note once we verified a fix is in place in one of those components.
|
|
||||||
|
|
||||||
## Final Result
|
## Final Result
|
||||||
|
|
||||||
Here is the full source of `src/App.js` that you should have if you followed this tutorial:
|
Here is the full source of `src/index.js` that you should have if you followed this tutorial:
|
||||||
|
|
||||||
```jsx:title=src/App.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/master/src/index.js jsx GITHUB-EMBED
|
||||||
import React, { Component } from 'react'
|
|
||||||
import './App.css'
|
|
||||||
import { Ocean } from '@oceanprotocol/squid'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
import asset from './asset'
|
|
||||||
|
|
||||||
const web3 = new Web3(window.web3.currentProvider)
|
## Git repository and CodeSandbox
|
||||||
window.ethereum.enable()
|
|
||||||
|
|
||||||
class App extends Component {
|
All code snippets in this tutorial are sourced from the [oceanprotocol/react-tutorial](https://github.com/oceanprotocol/react-tutorial) GitHub repository:
|
||||||
async componentDidMount() {
|
|
||||||
this.ocean = await new Ocean.getInstance({
|
|
||||||
web3Provider: web3,
|
|
||||||
nodeUri: 'http://localhost:8545',
|
|
||||||
aquariusUri: 'http://localhost:5000',
|
|
||||||
brizoUri: 'http://localhost:8030',
|
|
||||||
brizoAddress: '0x00bd138abd70e2f00903268f3db08f2d25677c9e',
|
|
||||||
parityUri: 'http://localhost:8545',
|
|
||||||
secretStoreUri: 'http://localhost:12001'
|
|
||||||
})
|
|
||||||
console.log('Finished loading contracts.')
|
|
||||||
}
|
|
||||||
|
|
||||||
async submitAsset() {
|
<repo name="react-tutorial"></repo>
|
||||||
const accounts = await this.ocean.accounts.list()
|
|
||||||
const ddo = await this.ocean.assets.create(asset, accounts[0])
|
|
||||||
console.log('Asset successfully submitted.')
|
|
||||||
console.log(ddo)
|
|
||||||
alert(
|
|
||||||
'Asset successfully submitted. Look into your console to see the response DDO object.'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async retrieveAssets() {
|
The final source of this tutorial is also available as a CodeSandbox:
|
||||||
this.search = await this.ocean.assets.search('10 Monkey Species Small')
|
|
||||||
console.log(this.search)
|
|
||||||
alert(
|
|
||||||
'Asset successfully retrieved. Look into your console to see the search response.'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async consumeAsset() {
|
[![Edit react-tutorial](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/oceanprotocol/react-tutorial/tree/master/?fontsize=14)
|
||||||
// get all accounts
|
|
||||||
const accounts = await this.ocean.accounts.list()
|
|
||||||
// get first asset
|
|
||||||
const consumeAsset = this.search.results[0]
|
|
||||||
// get service we want to execute
|
|
||||||
const service = consumeAsset.findServiceByType('Access')
|
|
||||||
// order service agreement
|
|
||||||
const agreement = await this.ocean.assets.order(
|
|
||||||
consumeAsset.id,
|
|
||||||
service.serviceDefinitionId,
|
|
||||||
accounts[0]
|
|
||||||
)
|
|
||||||
// consume it
|
|
||||||
await this.ocean.assets.consume(
|
|
||||||
agreement,
|
|
||||||
consumeAsset.id,
|
|
||||||
service.serviceDefinitionId,
|
|
||||||
accounts[0],
|
|
||||||
'',
|
|
||||||
0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="App App-header">
|
|
||||||
<h1>Marketplace app</h1>
|
|
||||||
<button onClick={() => this.submitAsset()}>Register asset</button>
|
|
||||||
<hr />
|
|
||||||
<button onClick={() => this.retrieveAssets()}>Retrieve assets</button>
|
|
||||||
<button onClick={() => this.consumeAsset()}>Consume asset</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
|
||||||
```
|
|
||||||
|
@ -9,7 +9,7 @@ This is a continuation of the [React App Setup](/tutorials/react-setup/) tutoria
|
|||||||
|
|
||||||
1. [React App Setup](/tutorials/react-setup/)
|
1. [React App Setup](/tutorials/react-setup/)
|
||||||
|
|
||||||
Open `src/App.js` from your `marketplace/` folder.
|
Open `src/index.js` from your `marketplace/` folder.
|
||||||
|
|
||||||
## Define Asset
|
## Define Asset
|
||||||
|
|
||||||
@ -19,167 +19,38 @@ To do that, we need to define the asset based on the [OEP-08](https://github.com
|
|||||||
|
|
||||||
Let's create a new file `src/asset.js` and fill it with:
|
Let's create a new file `src/asset.js` and fill it with:
|
||||||
|
|
||||||
```js:title=src/asset.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/asset.js js GITHUB-EMBED
|
||||||
const asset = {
|
|
||||||
base: {
|
|
||||||
name: '10 Monkey Species Small',
|
|
||||||
dateCreated: '2012-02-01T10:55:11Z',
|
|
||||||
author: 'Mario',
|
|
||||||
license: 'CC0: Public Domain',
|
|
||||||
price: '10',
|
|
||||||
files: [
|
|
||||||
{
|
|
||||||
index: 0,
|
|
||||||
contentType: 'application/zip',
|
|
||||||
checksum: '2bf9d229d110d1976cdf85e9f3256c7f',
|
|
||||||
checksumType: 'MD5',
|
|
||||||
contentLength: 12057507,
|
|
||||||
compression: 'zip',
|
|
||||||
encoding: 'UTF-8',
|
|
||||||
url:
|
|
||||||
'https://s3.amazonaws.com/datacommons-seeding-us-east/10_Monkey_Species_Small/assets/training.zip'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: 1,
|
|
||||||
contentType: 'text/txt',
|
|
||||||
checksum: '354d19c0733c47ef3a6cce5b633116b0',
|
|
||||||
checksumType: 'MD5',
|
|
||||||
contentLength: 928,
|
|
||||||
url:
|
|
||||||
'https://s3.amazonaws.com/datacommons-seeding-us-east/10_Monkey_Species_Small/assets/monkey_labels.txt',
|
|
||||||
resourceId: 'test'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: 2
|
|
||||||
}
|
|
||||||
],
|
|
||||||
checksum: '',
|
|
||||||
categories: ['image'],
|
|
||||||
tags: ['image data', 'classification', 'animals'],
|
|
||||||
type: 'dataset',
|
|
||||||
description: 'EXAMPLE ONLY ',
|
|
||||||
copyrightHolder: 'Unknown',
|
|
||||||
workExample: 'image path, id, label',
|
|
||||||
links: [
|
|
||||||
{
|
|
||||||
name: 'example model',
|
|
||||||
url:
|
|
||||||
'https://drive.google.com/open?id=1uuz50RGiAW8YxRcWeQVgQglZpyAebgSM'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'example code',
|
|
||||||
type: 'example code',
|
|
||||||
url: 'https://github.com/slothkong/CNN_classification_10_monkey_species'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url:
|
|
||||||
'https://s3.amazonaws.com/datacommons-seeding-us-east/10_Monkey_Species_Small/links/discovery/n5151.jpg',
|
|
||||||
name: 'n5151.jpg',
|
|
||||||
type: 'discovery'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url:
|
|
||||||
'https://s3.amazonaws.com/datacommons-seeding-us-east/10_Monkey_Species_Small/links/sample/sample.zip',
|
|
||||||
name: 'sample.zip',
|
|
||||||
type: 'sample'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
inLanguage: 'en'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default asset
|
Then import this asset definition at the top of `src/index.js`:
|
||||||
```
|
|
||||||
|
|
||||||
Then import this asset definition at the top of `src/App.js`:
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 5 GITHUB-EMBED
|
||||||
|
|
||||||
```js:title=src/App.js
|
|
||||||
// ...
|
|
||||||
import asset from './asset'
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Handle Asset Publishing
|
## Handle Asset Publishing
|
||||||
|
|
||||||
Now that we have an asset to submit, we need a function to handle it. Just before `render() {` let's add this function:
|
Now that we have an asset to submit, we need a function to handle it. Just before `render() {` let's add this `registerAsset` function:
|
||||||
|
|
||||||
```jsx:title=src/App.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 40-52 GITHUB-EMBED
|
||||||
// ...
|
|
||||||
async submitAsset() {
|
|
||||||
const accounts = await this.ocean.accounts.list()
|
|
||||||
const ddo = await this.ocean.assets.create(asset, accounts[0])
|
|
||||||
console.log('Asset successfully submitted.')
|
|
||||||
console.log(ddo)
|
|
||||||
alert(
|
|
||||||
'Asset successfully submitted. Look into your console to see the response DDO object.'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
The last thing we need is a button to start our registration inside the render function just after `<h1>Marketplace app</h1>`:
|
The last thing we need is a button to start our registration inside the `render()` function:
|
||||||
|
|
||||||
```jsx:title=src/App.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 111-113 GITHUB-EMBED
|
||||||
// ...
|
|
||||||
<button onClick={() => this.submitAsset()}>Register asset</button>
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
Tip: Before clicking the `Register asset` button, it might help to reload the page.
|
Note how we disable the button when Web3 is not available to reduce user confusion. Within the Ocean Protocol flow of registering, searching, and consuming, only searching is possible without Web3.
|
||||||
|
|
||||||
When you click on the `Register asset` button, you should get four separate dialog boxes from MetaMask, in a series, i.e. the second one only appears after you accept/approve the first one, and so on.
|
In your browser, you should now end up like this:
|
||||||
|
|
||||||
|
![React app with publish button](images/react-app-04.png)
|
||||||
|
|
||||||
|
When you click on the _Register asset_ button, you should get four separate dialog boxes from MetaMask, in a series, i.e. the second one only appears after you accept/approve the first one, and so on.
|
||||||
|
|
||||||
Have a look into `console.log` to see the various steps of the register process. If you have no errors in your `console.log`, then you have successfully registered an asset.
|
Have a look into `console.log` to see the various steps of the register process. If you have no errors in your `console.log`, then you have successfully registered an asset.
|
||||||
|
|
||||||
|
![Successful asset publishing](images/react-app-05.png)
|
||||||
|
|
||||||
## Final Result
|
## Final Result
|
||||||
|
|
||||||
Here is the full source of `src/App.js` that you should have if you followed this tutorial:
|
Here is the full source of `src/index.js` that you should have if you followed this tutorial:
|
||||||
|
|
||||||
```jsx:title=src/App.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 1-5,6-16,18-27,34-52,96-113,119-124 GITHUB-EMBED
|
||||||
import React, { Component } from 'react'
|
|
||||||
import './App.css'
|
|
||||||
import { Ocean } from '@oceanprotocol/squid'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
import asset from './asset'
|
|
||||||
|
|
||||||
const web3 = new Web3(window.web3.currentProvider)
|
**Move on to [Get & Use a Data Set](/tutorials/react-get-use-data-set/).**
|
||||||
window.ethereum.enable()
|
|
||||||
|
|
||||||
class App extends Component {
|
|
||||||
async componentDidMount() {
|
|
||||||
this.ocean = await new Ocean.getInstance({
|
|
||||||
web3Provider: web3,
|
|
||||||
nodeUri: 'http://localhost:8545',
|
|
||||||
aquariusUri: 'http://localhost:5000',
|
|
||||||
brizoUri: 'http://localhost:8030',
|
|
||||||
brizoAddress: '0x00bd138abd70e2f00903268f3db08f2d25677c9e',
|
|
||||||
parityUri: 'http://localhost:8545',
|
|
||||||
secretStoreUri: 'http://localhost:12001'
|
|
||||||
})
|
|
||||||
console.log('Finished loading contracts.')
|
|
||||||
}
|
|
||||||
|
|
||||||
async submitAsset() {
|
|
||||||
const accounts = await this.ocean.accounts.list()
|
|
||||||
const ddo = await this.ocean.assets.create(asset, accounts[0])
|
|
||||||
console.log('Asset successfully submitted.')
|
|
||||||
console.log(ddo)
|
|
||||||
alert(
|
|
||||||
'Asset successfully submitted. Look into your console to see the response DDO object.'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="App App-header">
|
|
||||||
<h1>Marketplace app</h1>
|
|
||||||
<button onClick={() => this.submitAsset()}>Register asset</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
|
||||||
```
|
|
||||||
|
|
||||||
Move on to [Get & Use a Data Set](/tutorials/react-get-use-data-set/).
|
|
||||||
|
@ -3,186 +3,183 @@ title: React App Setup
|
|||||||
description: This tutorial shows how you can build a basic [React](https://reactjs.org/) app with [Create React App](https://github.com/facebook/create-react-app) that uses the squid-js JavaScript package to publish a data set, get a data set, and more.
|
description: This tutorial shows how you can build a basic [React](https://reactjs.org/) app with [Create React App](https://github.com/facebook/create-react-app) that uses the squid-js JavaScript package to publish a data set, get a data set, and more.
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Git repository and CodeSandbox
|
||||||
|
|
||||||
|
All code snippets in this tutorial are sourced from the [oceanprotocol/react-tutorial](https://github.com/oceanprotocol/react-tutorial) GitHub repository:
|
||||||
|
|
||||||
|
<repo name="react-tutorial"></repo>
|
||||||
|
|
||||||
|
The final source of this tutorial is also available as a CodeSandbox:
|
||||||
|
|
||||||
|
[![Edit react-tutorial](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/oceanprotocol/react-tutorial/tree/master/?fontsize=14)
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- `Node.js` >= 10 is installed. You can check using `node -v`
|
- `Node.js` >= 10 is installed. You can check using `node -v`
|
||||||
- `npm` >= 5.2 is installed. You can check using `npm -v`
|
- `npm` >= 5.2 is installed. You can check using `npm -v`
|
||||||
- [Docker](https://www.docker.com/products/docker-desktop) & [Docker Compose](https://docs.docker.com/compose/install/)
|
- [Docker](https://www.docker.com/products/docker-desktop) & [Docker Compose](https://docs.docker.com/compose/install/)
|
||||||
- A Web3 capable browser, like Firefox/Chrome with [MetaMask](https://metamask.io) installed
|
- A Web3 capable browser, like Firefox/Chrome with [MetaMask](https://metamask.io) installed, [connected to Nile network](http://localhost:8000/tutorials/connect-to-networks/#connect-to-the-nile-testnet)
|
||||||
- `Spree`, a local Ocean test network
|
- Some Nile ETH from the Nile Faucet. You can either go to [commons.nile.dev-ocean.com/faucet](https://commons.nile.dev-ocean.com/faucet), or execute this command replacing `<YOUR ADDRESS>` with your MetaMask account address:
|
||||||
|
|
||||||
- Git clone the [oceanprotocol/barge](https://github.com/oceanprotocol/barge) repository, then in that directory:
|
|
||||||
- (Optional but recommended) Clean out all your old Docker stuff using `docker system prune --all --volumes`
|
|
||||||
- Use the startup script in Barge to run a [local Spree Testnet](https://docs.oceanprotocol.com/concepts/testnets/#a-spree-testnet-for-local-development):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export KEEPER_VERSION=v0.10.3 && \
|
curl --data '{"address": "<YOUR ADDRESS>", "agent": "curl"}' -H "Content-Type: application/json" -X POST https://faucet.nile.dev-ocean.com/faucet
|
||||||
export AQUARIUS_VERSION=v0.3.5 && \
|
|
||||||
export BRIZO_VERSION=v0.3.12 && \
|
|
||||||
./start_ocean.sh --no-pleuston
|
|
||||||
```
|
|
||||||
|
|
||||||
- Note that compiling and deploying the contracts in your local Docker network takes some time so it can take a few minutes until the network is ready to be interacted with. That usually is the case once `keeper-contracts_1` container doesn't show any messages anymore.
|
|
||||||
|
|
||||||
- [Some `Spree` Ether](/tutorials/get-ether-and-ocean-tokens/#get-ether-for-a-local-spree-testnet) in your MetaMask account. You can execute this, replacing `<YOUR ADDRESS>` with your MetaMask account address:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl --data '{"jsonrpc":"2.0","method":"personal_sendTransaction","params":[{"from":"0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e","to":"<YOUR ADDRESS>","value":"0x7FFFFFFFFFFFFFFFFFF"}, "node0"],"id":0}' -H "Content-Type: application/json" -X POST localhost:8545
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## New Create React App
|
## New Create React App
|
||||||
|
|
||||||
First, kickstart your new React app by creating a boilerplate with Create React App:
|
We are going to use Create React App to bootstrap our React app. You could use `npx create-react-app marketplace` but it creates more files than needed for the scope of this tutorial.
|
||||||
|
|
||||||
|
So let's go minimal and build up our app from scratch with this structure:
|
||||||
|
|
||||||
|
```text
|
||||||
|
marketplace/
|
||||||
|
├── package.json
|
||||||
|
├── public/
|
||||||
|
├──── index.html
|
||||||
|
├── src/
|
||||||
|
├──── index.js
|
||||||
|
```
|
||||||
|
|
||||||
|
First, create a new project folder for your new app, e.g. `marketplace`. Within that, add a new file `package.json` with the following content:
|
||||||
|
|
||||||
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/package.json json GITHUB-EMBED
|
||||||
|
|
||||||
|
Notice the `@oceanprotocol/squid` dependency, which is the [Ocean Protocol JavaScript library](https://github.com/oceanprotocol/squid-js). Save that file, and in your terminal install the dependencies we have just defined in `package.json`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx create-react-app marketplace
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a folder named `marketplace` with a boilerplate React app. Go into that new folder and add the [Ocean Protocol JavaScript library](https://github.com/oceanprotocol/squid-js) to the app's dependencies:
|
Then create the HTML file used to render the React app into. For that, create a folder `public/` and in it a file `index.html` with the following content:
|
||||||
|
|
||||||
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/public/index.html html GITHUB-EMBED
|
||||||
|
|
||||||
|
## Add Basic Markup
|
||||||
|
|
||||||
|
Create a new folder `src/` and within that a `index.js` file with the following content as our base, where we already import squid-js and web3.js:
|
||||||
|
|
||||||
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 1-4,6,14,97-108,119-124 GITHUB-EMBED
|
||||||
|
|
||||||
|
At this point you can start up the app and see the result in your browser:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd marketplace/
|
npm start
|
||||||
npm install @oceanprotocol/squid@0.6.2
|
|
||||||
```
|
```
|
||||||
|
|
||||||
At this point you can already run `npm start` which starts the app in your browser at [localhost:3000](http://localhost:3000):
|
Go to [localhost:3000](http://localhost:3000) to inspect your newly created app:
|
||||||
|
|
||||||
![React App 01](images/react-app-01.png)
|
![Initial React App](images/react-app-01.png)
|
||||||
|
|
||||||
## Add Markup & Web3
|
## Setup Web3
|
||||||
|
|
||||||
Let's make it ours, open `src/App.js` and replace the whole source with:
|
We already are importing web3.js but we still need to enable account access for the browsers supporting it, and make sure nothing breaks in browsers which are not Web3-capable.
|
||||||
|
|
||||||
```jsx:title=src/App.js
|
To do that we add a simple check at top of `src/index.js` and then enable account access with:
|
||||||
import React, { Component } from 'react'
|
|
||||||
import './App.css'
|
|
||||||
|
|
||||||
class App extends Component {
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 7-12 GITHUB-EMBED
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="App App-header">
|
|
||||||
<h1>Marketplace app</h1>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
And let's also output some warning for non-Web3 browsers within our `render()` function:
|
||||||
```
|
|
||||||
|
|
||||||
Below the `import './App.css'` line, let's import the packages we installed, set up web3 and unlock MetaMask accounts (if locked):
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 109 GITHUB-EMBED
|
||||||
|
|
||||||
```jsx{3-7}:title=src/App.js
|
This should give you the following markup:
|
||||||
import React, { Component } from 'react'
|
|
||||||
import './App.css'
|
|
||||||
import { Ocean } from '@oceanprotocol/squid'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
|
|
||||||
const web3 = new Web3(window.web3.currentProvider)
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 1-4,6-14,97-109,119-124 GITHUB-EMBED
|
||||||
window.ethereum.enable()
|
|
||||||
|
|
||||||
class App extends Component {
|
After those steps go to your browser. You should see MetaMask asking you to allow access to your account:
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="App App-header">
|
|
||||||
<h1>Marketplace app</h1>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
![MetaMask confirmation](images/react-app-02.png)
|
||||||
```
|
|
||||||
|
|
||||||
After those steps you should see this, and MetaMask should have asked you to allow access to your account:
|
> Note: If you see an error like `inpage.js:1 MetaMask - RPC Error: Internal JSON-RPC error.` in your browser console, don't worry about it. It's a MetaMask thing and won't affect functionality.
|
||||||
|
|
||||||
![React App 02](images/react-app-02.png)
|
|
||||||
![React App 03](images/react-app-03.png)
|
|
||||||
|
|
||||||
> Note: If you see an error like `inpage.js:1 MetaMask - RPC Error: Internal JSON-RPC error.` in your browser console, don't worry about it. It's a MetaMask thing.
|
|
||||||
|
|
||||||
## Create Ocean Instance
|
## Create Ocean Instance
|
||||||
|
|
||||||
Now that we are successfully connected with Web3, we can set up our Ocean instance.
|
Now that we are successfully connected with Web3, we can set up our Ocean instance.
|
||||||
|
|
||||||
At the beginning of your component , create a new Ocean instance with all configuration within the `componentDidMount` lifecycle method. All Ocean Protocol operations can be executed from this Ocean instance.
|
At the beginning of your component, create a new Ocean instance with all required endpoint configurations within the `componentDidMount` lifecycle method. All Ocean Protocol operations can be executed from this Ocean instance.
|
||||||
|
|
||||||
```jsx{10-21}:title=src/App.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 15-16,18-27,34-38 GITHUB-EMBED
|
||||||
import React, { Component } from 'react'
|
|
||||||
import './App.css'
|
|
||||||
import { Ocean } from '@oceanprotocol/squid'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
|
|
||||||
const web3 = new Web3(window.web3.currentProvider)
|
This will initiate a connection to all Ocean components in Nile, load the contracts, and finally store the Ocean object in the local component state for reuse.
|
||||||
window.ethereum.enable()
|
|
||||||
|
|
||||||
class App extends Component {
|
We also set the `verbose` option of squid-js so we better see what's going on.
|
||||||
async componentDidMount() {
|
|
||||||
this.ocean = await new Ocean.getInstance({
|
|
||||||
web3Provider: web3,
|
|
||||||
nodeUri: 'http://localhost:8545',
|
|
||||||
aquariusUri: 'http://localhost:5000',
|
|
||||||
brizoUri: 'http://localhost:8030',
|
|
||||||
brizoAddress: '0x00bd138abd70e2f00903268f3db08f2d25677c9e',
|
|
||||||
parityUri: 'http://localhost:8545',
|
|
||||||
secretStoreUri: 'http://localhost:12001'
|
|
||||||
})
|
|
||||||
console.log('Finished loading contracts.')
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="App App-header">
|
|
||||||
<h1>Marketplace app</h1>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
|
||||||
```
|
|
||||||
|
|
||||||
## Final Result
|
## Final Result
|
||||||
|
|
||||||
That's it, if you have no errors in your `console.log` then you have successfully initialized an Ocean instance in your brand new React app and you are ready for the [next part of this tutorial](/tutorials/react-publish-data-set/).
|
That's it, if you have no errors in your `console.log` then you have successfully initialized an Ocean instance in your brand new React app and you are ready for the [next part of this tutorial](/tutorials/react-publish-data-set/).
|
||||||
|
|
||||||
![React App 04](images/react-app-04.png)
|
![Initial React App with Ocean initiated](images/react-app-03.png)
|
||||||
|
|
||||||
Here is the full source of `src/App.js` that you should have if you followed this tutorial:
|
Here is the full source of `src/index.js` that you should have if you followed this tutorial:
|
||||||
|
|
||||||
```jsx:title=src/App.js
|
GITHUB-EMBED https://github.com/oceanprotocol/react-tutorial/blob/2765a7e6ae9a948d311d3949636cf832d2664900/src/index.js jsx 1-4,6-16,18-27,34-38,96-109,119-124 GITHUB-EMBED
|
||||||
import React, { Component } from 'react'
|
|
||||||
import './App.css'
|
|
||||||
import { Ocean } from '@oceanprotocol/squid'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
|
|
||||||
const web3 = new Web3(window.web3.currentProvider)
|
**Move on to [Publish a Data Set](/tutorials/react-publish-data-set/).**
|
||||||
window.ethereum.enable()
|
|
||||||
|
|
||||||
class App extends Component {
|
## Bonus: Connect against local Spree network
|
||||||
async componentDidMount() {
|
|
||||||
this.ocean = await new Ocean.getInstance({
|
|
||||||
web3Provider: web3,
|
|
||||||
nodeUri: 'http://localhost:8545',
|
|
||||||
aquariusUri: 'http://localhost:5000',
|
|
||||||
brizoUri: 'http://localhost:8030',
|
|
||||||
brizoAddress: '0x00bd138abd70e2f00903268f3db08f2d25677c9e',
|
|
||||||
parityUri: 'http://localhost:8545',
|
|
||||||
secretStoreUri: 'http://localhost:12001'
|
|
||||||
})
|
|
||||||
console.log('Finished loading contracts.')
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
[_Spree_](https://docs.oceanprotocol.com/concepts/testnets/#a-spree-testnet-for-local-development), a local Ocean test network, can be used instead of remotely connecting to Nile. For this you first have to get up the Spree network by using [oceanprotocol/barge](https://github.com/oceanprotocol/barge).
|
||||||
return (
|
|
||||||
<div className="App App-header">
|
|
||||||
<h1>Marketplace app</h1>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
### Run Spree with Barge
|
||||||
|
|
||||||
|
Clone the barge repository and use its startup script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/oceanprotocol/barge.git
|
||||||
|
cd barge/
|
||||||
|
|
||||||
|
./start_ocean.sh --no-pleuston
|
||||||
```
|
```
|
||||||
|
|
||||||
Move on to [Publish a Data Set](/tutorials/react-publish-data-set/).
|
Note that compiling and deploying the contracts in your local Docker network takes some time so it can take a few minutes until the network is ready to be interacted with. That usually is the case once `keeper-contracts_1` container doesn't show any messages anymore.
|
||||||
|
|
||||||
|
### Copy Contract Artifacts
|
||||||
|
|
||||||
|
At the end of the contract compiling and deploying you need to copy the resulting _Spree_ contract artifacts from the Docker container to your local `@oceanprotocol/keeper-contracts` dependency folder. The _keeper-contracts_ Docker container will output all artifacts in a hidden folder in your home folder so you can copy from there:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp ~/.ocean/keeper-contracts/artifacts/* ./node_modules/@oceanprotocol/keeper-contracts/artifacts/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Spree Ether
|
||||||
|
|
||||||
|
You will also need some [_Spree_ Ether](/tutorials/get-ether-and-ocean-tokens/#get-ether-for-a-local-spree-testnet) in your MetaMask account. You can execute this, replacing `<YOUR ADDRESS>` with your MetaMask account address:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --data '{"address": "<YOUR ADDRESS>", "agent": "curl"}' -H "Content-Type: application/json" -X POST http://localhost:3001/faucet
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adjust App Config
|
||||||
|
|
||||||
|
Finally, move back to your marketplace React app and modify the Ocean instance config in `src/index.js` to use the Spree endpoints:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const ocean = await new Ocean.getInstance({
|
||||||
|
web3Provider: web3,
|
||||||
|
nodeUri: 'http://localhost:8545',
|
||||||
|
aquariusUri: 'http://aquarius:5000',
|
||||||
|
brizoUri: 'http://localhost:8030',
|
||||||
|
brizoAddress: '0x00bd138abd70e2f00903268f3db08f2d25677c9e',
|
||||||
|
secretStoreUri: 'http://localhost:12001',
|
||||||
|
verbose: true
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
> If you are on macOS, you need to additionally tweak your `/etc/hosts` file so Brizo can connect to Aquarius within Docker. This is only required on macOS and is a [known limitation of Docker for Mac](https://docs.docker.com/docker-for-mac/networking/#known-limitations-use-cases-and-workarounds):
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> sudo vi /etc/hosts
|
||||||
|
>
|
||||||
|
> # add this line, and save
|
||||||
|
> 127.0.0.1 aquarius
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> And then use `aquariusUri: 'http://aquarius:5000'` in your Ocean instance config.
|
||||||
|
|
||||||
|
Then start up the app as usual:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
**Move on to [Publish a Data Set](/tutorials/react-publish-data-set/).**
|
||||||
|
@ -83,9 +83,9 @@ module.exports = {
|
|||||||
resolve: 'gatsby-remark-github',
|
resolve: 'gatsby-remark-github',
|
||||||
options: {
|
options: {
|
||||||
marker: 'GITHUB-EMBED',
|
marker: 'GITHUB-EMBED',
|
||||||
insertEllipsisComments: true,
|
insertEllipsisComments: false,
|
||||||
ellipsisPhrase: '...',
|
ellipsisPhrase: '...',
|
||||||
useCache: true,
|
useCache: false,
|
||||||
cacheKey: 'gatsby-remark-github-v1',
|
cacheKey: 'gatsby-remark-github-v1',
|
||||||
token: process.env.GITHUB_TOKEN
|
token: process.env.GITHUB_TOKEN
|
||||||
}
|
}
|
||||||
|