//tips
//smart contract
New.jsのnew campaignページ作成の続きを行なっていく。
前回同様にreact.semantic-uiの機能を参照しながら作成。
インプットフォームを組み込む。下記のような形になった。
import React,{Comment, Component} from 'react';
//2階層上のフォルダの中からインポート
import Layout from '../../components/Layout';
import {Form,Button,Input} from 'semantic-ui-react';
import factory from '../../ethereum/factory';
import web3 from '../../ethereum/web3';//web3.eth.getAccounts();使用のため
class CampaignNew extends Component{
//イベントハンドラーの設定用
state={
minimumContribution:''
};
//eventが発生したら自動的に呼ばれる
//contract上の関数を呼び出す時にはasyncが使われる
onSubmit=async (event)=>{
event.preventDefault();
const accounts=await web3.eth.getAccounts();
//新たなキャンペーンを作成
await factory.methods
.createCampaign(this.state.minimumContribution)
.send({
from:accounts[0]
});
};
render(){
return(
<Layout>
<h3>create a Campaign</h3>
<Form onSubmit={this.onSubmit}>
<Form.Field>
<label>Minimum Contribution</label>
<Input
label="wei"
labelPosition="right"
value={this.state.minimumContribution}
onChange={event=>
this.setState({minimumContribution:event.target.value})}
/>
</Form.Field>
<Button primary>Create!</Button>
</Form>
</Layout>
);
}
}
export default CampaignNew;
ただ、このままではブラウザではエラーをうまく表示できないことがわかった。別途実装する必要がありそう。
import React,{Comment, Component} from 'react';
//2階層上のフォルダの中からインポート
import Layout from '../../components/Layout';
import {Form,Button,Input,Message} from 'semantic-ui-react';
import factory from '../../ethereum/factory';
import web3 from '../../ethereum/web3';//web3.eth.getAccounts();使用のため
class CampaignNew extends Component{
//イベントハンドラーの設定用
state={
minimumContribution:'',
errorMessage:'',
loading:false//spiner用
};
//eventが発生したら自動的に呼ばれる
//contract上の関数を呼び出す時にはasyncが使われる
onSubmit=async (event)=>{
event.preventDefault();
this.setState({loading:true, errorMessage=''});//errorMessage=''は再度提出時に前回メッセージをクリアする
try{
const accounts=await web3.eth.getAccounts();
//新たなキャンペーンを作成
await factory.methods
.createCampaign(this.state.minimumContribution)
.send({
from:accounts[0]
});
}catch(err){
this.setState({errorMessage:err.message});
}
this.setState({loading:false});//メタマスクの処理が完了したらloadingスピナーの動きを解除
//スピナー状態にすることで複数回submitされるのを防ぐ
};
//errorがbool認識されてしまっているので!!this.state.errorMessage
//文字列が入っていればtrueを返すようにしている
render(){
return(
<Layout>
<h3>create a Campaign</h3>
<Form onSubmit={this.onSubmit} error={!!this.state.errorMessage}>
<Form.Field>
<label>Minimum Contribution</label>
<Input
label="wei"
labelPosition="right"
value={this.state.minimumContribution}
onChange={event=>
this.setState({minimumContribution:event.target.value})}
/>
</Form.Field>
<Message error header="Oops" content={this.state.errorMessage}/>
<Button loading={this.state.loading} primary>Create!</Button>
</Form>
</Layout>
);
}
}
export default CampaignNew;
また、npm install next-routes --legacy-peer-depsを導入して、フォルダ内の保存の際にアドレスも加えられるようにしておく。
この場合にはserver.jsでnextアプリを立ち上げ、routes.jsで異なるパスを定義してあげる形を取る。
const routes=require('next-routes')();
//オフィシャルドキュメント通り()をつける
//require()で関数を返すので
module.exports=routes;
すごいシンプル。
serverの方も作成。
const { Console } = require('console');
const {createServer}=require('http');
const next=require('next');
//新しいappインスタンスを作成
const app=next({
dev:process.env.NODE_ENV !=='production'
//productionモードでないことを確認
});
const routes=require('./routes');
const handler= routes.getRequestHandler(app);
app.prepare().then(()=>{
createServer(handler).listen(3000,(err)=>{
if(err)throw err;
Console.log('Ready on localhost:3000');
//npm run devをターミナルで実行するときちんと表示される。
//"dev": "node server.js"に変更しておく
});
});
これをもとにヘッダーを改変し、クリック時にリンクの場所に遷移するようにさせる。
import React from 'react';
import {Menu, MenuHeader} from 'semantic-ui-react';
import {Link} from '../routes';
//menuとlinkは一部衝突するので調整が必要
const Layout = (props) => {
return(
<Menu style={{marginTop:'10px'}}>
<Link route='/'>
<a className="item">Crowdcoin
</a>
</Link>
<Menu.Menu position="right">
<Link route='/'>
<a className="item">Campaigns
</a>
</Link>
<Link route='/campaigns/new'>
<a className="item">+
</a>
</Link>
</Menu.Menu>
</Menu>
);
};
export default Layout;
Layoutに組み込まれているHeaderの方を修正。