The original link

In the previous section we made no changes to the Reach program to make rock-Paper-Scissors run as a command-line application. In this section, we still don’t need to modify the Reach program, we just replace the Web interface with the command line interface. This tutorial uses react.js, but the methods are applicable to any Web framework.

If you haven’t used React before, here’s how it works:

  • React programs are JavaScript programs that use a special library that allows you to add HTML to your JavaScript body programs.
  • React has a special compiler that combines a set of JavaScript programs and all their dependencies into a large file that can be deployed on a static Web server. This is called “packing”.
  • When you develop and test with React, you can run a special development Web server that monitors the package for updates every time you modify the source file, so you don’t have to run the compiler as often.
  • When running./ Reach React, it automatically starts the development server and gives you access to it http://localhost:3000/.

As before, in this tutorial, we assume that ethereum will be used for deployment (and testing). The Reach Web application relies on a Web browser to provide access to consensus Network accounts and their associated wallets. On Ethereum, the standard wallet is the MetaMask. If you want to test the code here, you need to install and set up MetaMask. Also, MetaMask doesn’t support multiple instance accounts, so if you want to test rock-paper-Scissors locally! You need to have two separate browser instances (Firefox +Chrome) : one as Alice and one as Bob. – The code in this section does not build on the previous section. Reach comes with a handy command to delete configuration files:

$ ./reach unscaffold

Again, we don’t need the previous index.mjs file because we’ll write it completely from scratch to use React. You can run the following command to remove it:

$ rm index.mjs

Alternatively, you can copy the index.rsh file to a new directory and start working from there. — This code adds index.css and some views. These details are trivial and not specific to Reach, so we will not explain the details of these documents. To run it locally, you need to download those files. The directory should look like this:

.
├ ─ ─ index. The CSS
├ ─ ─ index. Js
├ ─ ─ index. RSH
└ ─ ─ views
├ ─ ─ AppViews. Js
├ ─ ─ AttacherViews. Js
├ ─ ─ DeployerViews. Js
├ ─ ─ PlayerViews. Js
└ ─ ─ render. Js

— We will focus on tut-9/index.js because tut-9/index.rsh is the same as the previous section. tut-9/index.js

 1    import React from 'react';
 2    import AppViews from './views/AppViews';
 3    import DeployerViews from './views/DeployerViews';
 4    import AttacherViews from './views/AttacherViews';
 5    import {renderDOM, renderView} from './views/render';
 6    import './index.css';
 7    import * as backend from './build/index.main.mjs';
 8    import * as reach from '@reach-sh/stdlib/ETH';
 9.// ...
Copy the code
  • On lines 1 through 6, we import the view code and CSS.
  • At line 7, we import the compiled back end.
  • In line 8, we import stdlib as reach.

— To run on Algorand, change the import at line 8.

Import * from @reach-sh/stdlib/ALGO as reachCopy the code

tut-9/index.js

.// ...
10    const handToInt = {'ROCK': 0.'PAPER': 1.'SCISSORS': 2};
11    const intToOutcome = ['Bob wins! '.'Draw! '.'Alice wins! '];
12    const {standardUnit} = reach;
13    const defaults = {defaultFundAmt: '10'.defaultWager: '3', standardUnit};
14.// ...
Copy the code

On these lines, we define some useful constants and default values that correspond to the enumeration we defined in Reach. — We started by defining our App as a React component and telling it what to do when it’s mounted. “Mount” is the React term, which means start.

Figure 1: ConnectAccount view. See also: AppView.

tut-9/index.js

.// ...
15    class App extends React.Component {
16      constructor(props) {
17        super(props);
18        this.state = {view: 'ConnectAccount'. defaults};19      }
20      async componentDidMount() {
21        const acc = await reach.getDefaultAccount();
22        const balAtomic = await reach.balanceOf(acc);
23        const bal = reach.formatCurrency(balAtomic, 4);
24        this.setState({acc, bal});
25        try {
26          const faucet = await reach.getFaucet();
27          this.setState({view: 'FundAccount', faucet});
28        } catch (e) {
29          this.setState({view: 'DeployerOrAttacher'});
30        }
31}..// ...
Copy the code

tut-9/index.js

.// ...
39      render() { return renderView(this, AppViews); }
40    }
41.// ...
Copy the code
  • In line 18, we initialize the component state to display the ConnectAccount view (Figure 1).
  • In lines 20 through 31, we connect to the React componentDidMount lifecycle event, which is called when the component starts.
  • In line 21, we use getDefaultAccount, which accesses the default browser account. For example, when used with Ethereum, it can discover the currently selected MetaMask account.
  • In line 26, we use getFaucet to try to access the Reach developer test network faucet.
  • In line 27, if getFaucet succeeds, we set the component state to display the FundAccount view (Figure 2).
  • In line 29, if getFaucet does not succeed, we set the component state to jump to the DeployerOrAttacher view (Figure 3).
  • At line 39, we render the appropriate view from Tut-9 /views/ appviewws.js.

Figure 2: Fund account view. See also: AppView.

Next, we define callback on the App, which is what to do when the user clicks some button. tut-9/index.js

. .// ...
32     async fundAccount(fundAmount) {
33       await reach.transfer(this.state.faucet, this.state.acc, reach.parseCurrency(fundAmount));
34       this.setState({view: 'DeployerOrAttacher'});
35     }
36     async skipFundAccount() { this.setState({view: 'DeployerOrAttacher'}); }.. .// ...
Copy the code
  • In lines 32 through 35, we define what happens when the user clicks on Fund Account.
  • In line 33, we transfer funds from the tap to the user’s account.
  • In line 34, we set the component state to show the DeployerOrAttacher view (Figure 3).
  • In line 36, we define what to do when the user clicks the Skip button, which is to set the component state to display the Deployer Or Attacher view (Figure 3).

Figure 3: The Deployer or Attacher view. AppViews.DeployerOrAttacher

tut-9/index.js

.// ...
37      selectAttacher() { this.setState({view: 'Wrapper'.ContentView: Attacher}); }
38      selectDeployer() { this.setState({view: 'Wrapper'.ContentView: Deployer}); }..// ...
Copy the code

In lines 37 and 38, we set up the child components based on whether the user clicks Deployer or Attacher. — Next, we’ll define the Player as the React component, which will be extended by Alice and Bob’s specialized components.

Figure 4: GetHand view. See also: PlayerView.

Our Web front end needs to implement a participant interface for players, which we define as tu-9 /index.rsh

.// ...
20    const Player =
21          { ...hasRandom,
22            getHand: Fun([], UInt),
23            seeOutcome: Fun([UInt], Null),
24informTimeout: Fun([], Null) }; .// ...
Copy the code

We will provide these callbacks directly through the React component. tut-9/index.js

.// ...
42    class Player extends React.Component {
43      random() { return reach.hasRandom.random(); }
44      async getHand() { // Fun([], UInt)
45        const hand = await new Promise(resolveHandP= > {
46          this.setState({view: 'GetHand'.playable: true, resolveHandP});
47        });
48        this.setState({view: 'WaitingForResults', hand});
49        return handToInt[hand];
50      }
51      seeOutcome(i) { this.setState({view: 'Done'.outcome: intToOutcome[i]}); }
52      informTimeout() { this.setState({view: 'Timeout'}); }
53      playHand(hand) { this.state.resolveHandP(hand); }
54    }
55.// ...
Copy the code
  • In line 43, we provide the hasRandom callback function
  • In lines 44 through 50, we provide the getHand callback function.
  • In lines 45 through 47, we set the component state to display the Get Hand view (Figure 4) and wait for a Promise that can be resolved through user interaction.
  • In line 48, after the Promise resolution, we set the component state to show the Waiting For Results view (Figure 5).
  • In lines 51 and 52, we provide seeOutcome and informTimeout callbacks that set the component state to display the Done view (Figure 6) and the Timeout view (Figure 7), respectively.
  • In line 53, we define what happens when the user clicks rock, Paper, Scissors: Line 45 promises are resolved.

Figure 5: WaitingForResults view. See also: PlayerViews WaitingForResultsFigure 6: Complete view. See also: PlayerView. DoneFigure 7: Timeout view. See also: PlayerViews. A Timeout

Next, we’ll define Deployer as Alice’s React component, which extends Player.

Figure 8: SetWager view. See also: DeployerView.Figure 9: Deployment view.

Our Web front end needs to realize Alice’s participant interaction interface, which we define as tu-9 /index.rsh

.// ...
25    const Alice =
26          { ...Player,
27wager: UInt }; .// ...
Copy the code

We will provide the bet values and define some button handlers to trigger the deployment of the contract. tut-9/index.js

.// ...
56    class Deployer extends Player {
57      constructor(props) {
58        super(props);
59        this.state = {view: 'SetWager'};
60      }
61      setWager(wager) { this.setState({view: 'Deploy', wager}); }
62      async deploy() {
63        const ctc = this.props.acc.deploy(backend);
64        this.setState({view: 'Deploying', ctc});
65        this.wager = reach.parseCurrency(this.state.wager); // UInt
66        backend.Alice(ctc, this);
67        const ctcInfoStr = JSON.stringify(await ctc.getInfo(), null.2);
68        this.setState({view: 'WaitingForAttacher', ctcInfoStr});
69      }
70      render() { return renderView(this, DeployerViews); }
71    }
72.// ...
Copy the code
  • At line 59, we set the component state to display the SetWager view (Figure 8).
  • In line 61, we define what to do when the user clicks the Set Wager button, which is to Set the component state to display the Deploy view (Figure 9).
  • In lines 62-69, we define what to do when the user clicks the Deploy button.
  • In line 63, we call acc.deploy, which triggers the deployment of the contract.
  • In line 64, we set the component state to display the deployment view (Figure 10).
  • In line 65, we set the bet property.
  • At line 66, we start running the Reach program as Alice, using the React component as the actor interface object.
  • In lines 67 and 68, we set the component state to display the WaitingForAttacher view (Figure 11), which displays the deployed contract information as JSON.
  • In line 70, we from tut – 9 / views/DeployerViews. Js. Render the appropriate view in.

Figure 10: Deployment view. See deployment ViewFigure 11: WaitingForAttacher view. DeployerViews.WaitingForAttacher

Figure 12: Attacher view.Figure 13: Attached view, see attachment View

Our Web front end needs to implement a participant interface for Bob, which we define as tu-9 /index.rsh

.// ...
28    const Bob =
29          { ...Player,
30acceptWager: Fun([UInt], Null) }; .// ...
Copy the code

We will provide acceptWager callbacks and define some button handlers to attach to the deployed contract. tut-9/index.js

.// ...
73    class Attacher extends Player {
74      constructor(props) {
75        super(props);
76        this.state = {view: 'Attach'};
77      }
78      attach(ctcInfoStr) {
79        const ctc = this.props.acc.attach(backend, JSON.parse(ctcInfoStr));
80        this.setState({view: 'Attaching'});
81        backend.Bob(ctc, this);
82      }
83      async acceptWager(wagerAtomic) { // Fun([UInt], Null)
84        const wager = reach.formatCurrency(wagerAtomic, 4);
85        return await new Promise(resolveAcceptedP= > {
86          this.setState({view: 'AcceptTerms', wager, resolveAcceptedP});
87        });
88      }
89      termsAccepted() {
90        this.state.resolveAcceptedP();
91        this.setState({view: 'WaitingForTurn'});
92      }
93      render() { return renderView(this, AttacherViews); }
94    }
95.// ...
Copy the code
  • In line 76, we initialize the component state to display the Attach view (Figure 12).
  • In lines 78 through 82, we define what happens when the user clicks the Attach button.
  • At line 79, we call acc.attach
  • In line 80, we set the component state to display the additional view (Figure 13).
  • At line 81, we start running the Reach program as Bob, using the React component as the actor interaction interface object.
  • On lines 83 through 88, we define the acceptWager callback function.
  • In lines 85 through 87, we set the component state to display the Accept Terms view (Figure 14) and wait for a Promise that can be resolved through user interaction.
  • In lines 89 through 92, we define what happens when the user clicks Accept Terms and the Pay Wager button: In line 90 the Promise is resolved, and we set the component state to show the Waiting For Turn view (Figure 15).
  • At line 93, we render the appropriate view from Tut-9 /views/ attacherviews.js

Figure 14: AcceptTerms view, see: AttacherViews. AcceptTermsFigure 15: The WaitingForTurn view. See also: AttacherViews WaitingForTurn

– tut – 9 / index. Js

.// ...
96    renderDOM(<App />);
Copy the code

Finally, we call a little helper function in Tut-9 /views/render.js to render our App component.

To facilitate running the React development server, you can call:

$ ./reach react

To run the React development server using Algorand, you can call:

$ REACH_CONNECTOR_MODE=ALGO./reach react

If you want to use Reach in your own JavaScript projects, you can call:

$ npm install @reach-sh/stdlib

The Reach library is constantly being improved and updated. If you are experiencing problems with the Node.js package, please try updating it!

As usual, you can compile the Reach program index.rsh into the back-end build artifact build/index.main.mjs using:

$ ./reach run

Now our rock-paper-scissors implementation is on the browser! We can use callbacks in the participant interface to display and collect information to the user through any Web UI framework we choose. If we wanted to publish the application, we would take the static files generated by React and host them on a Web server. These files are embedded in your compiled Reach program, so there is no choice but to make them available to the outside world. In the next section, we’ll summarize what we’ve achieved and guide you through the next steps on your journey to mastery of decentralized applications.

Do you know? :

True or false: Reach integrates all Web interface libraries, such as React and Vue, because the Reach front end is just a normal JavaScript program.

The answer is: yes

Do you know? :

True or false: Reach speeds up your React development by embedding the React development server and deployment process to test the React application locally.

The answer is: yes

2.8 Interaction and autonomous operation

Next: 2.10 Future outlook