前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于eos的Dapp开发--元素战争(三)

基于eos的Dapp开发--元素战争(三)

作者头像
用户2569546
发布2021-11-23 10:39:56
8820
发布2021-11-23 10:39:56
举报
文章被收录于专栏:eosfanseosfans

我们在前面的章节中先后介绍了一个基于EOS的Dapp中主要包含有哪些内容以及智能合约的编写过程和规范,今天我们来谈谈一个Dapp开发中另一个不可或缺的内容,即前端是如何开发的。

在本次课程之前需要指出:在本课程中将涉及到private-key的操作,由于这仅仅是个教程所以在这里故意将private-key的使用简单化了,在我们自己进行DAPP的开发过程中是不可取的,一定要注意保护好用户的隐私以及自己Dapp智能合约的账户安全。

上一节中我们在智能合约中实现了一个名为login的ation,用户通过前端进行登录,然后使用一个名为eosjs的Javascript的库提交请求到智能合约,在本节中我们还将使用另外一个JavaScript库Redux来处理React app的状态信息,Redux并不仅仅是为了React而设计的,因此我们要使用一个react-redux模块来实现这些。首先通过以下命令来安装相应的库:

代码语言:javascript
复制
npm install --save redux
npm install --save react-redux
npm install --save eosjs

我们来看Login.jsp文件,其中包含了用户名输入框,private-key输入框,提交按钮三个部分,当然你现在点击这个按钮是不会有任何反应的,button是react的一个组件,我们可以在src/components/Button看到这些内容,button类封装了我们整个web app的按钮的绘制和样式,通过复用这个组件,我们可以避免大规模的使用CSS等来构建前端页面。

代码语言:javascript
复制
import React, { Component } from 'react';
import { connect } from 'react-redux';
// button组件
import { Button } from 'components';
// 服务组件
import { UserAction } from 'actions';
import { ApiService } from 'services';

class Login extends Component {

  constructor(props) {
    super(props);
    // 构造函数来存储数据的状态和错误信息
    this.state = {
      form: {
        username: '',
        key: '',
        error: '',
      },
    }
    // 绑定消息函数
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // 响应键盘上的动作
  handleChange(event) {
    const { name, value } = event.target;
    const { form } = this.state;

    this.setState({
      form: {
        ...form,
        [name]: value,
        error: '',
      },
    });
  }

  // 用户点击提交按钮的相应
  handleSubmit(event) {
    event.preventDefault();
    const { form } = this.state;
    const { setUser } = this.props;
    //通过apiService发送登录的trx到智能合约,如果登录成功了保存用户名到redux,如果失败了向用户展示错误信息
    return ApiService.login(form)
      .then(() => {
        setUser({ name: form.username });
      })
      .catch(err => {
        this.setState({ error: err.toString() });
      });
  }

我们首先要把登录框放到main app中,为此我们来编辑下这个文件src/components/App/App.jsx。接下来我们将在登录框中构建并绑定一些响应函数,需要存储登录的数据然后提交用户的登录信息到智能合约中去,然后通过一个构造器和两个函数来实现这些。

  • 构造函数--用来初始化一些信息同时绑定两个响应函数,这样我们就可以方便的查询组件的状态。
  • handleChange函数--当用户更新用户名或者密码的时候就会被触发,然后更新组件的状态。
  • handleSubmit函数--发送用户的登录请求到智能合约。

上面说了这么多,其实前端和智能合约之间并没有产生交互,接下来我们来看如何实现交互。在frontend文件夹中我们可以看到.env文件,它用来存储一些变量的地方如,类似于环境变量:

  • REACT_APP_EOS_HTTP_ENDPOINT--接口的地址
  • REACT_APP_EOS_CONTRACT_NAME--合约的名字

接下来让我们尝试创建一个服务端组件,命名为ApiService,这个服务组件将会让前端和智能合约联系起来。在创建服务组件的时候我们使用了takeAction方法,该方法将发送transaction信息到智能合约。在这里我们使用了eosjs中的三个库:

  • RPC
  • SignatureProvider
  • Api

关于这三个库的相关信息也可以参考下eosjs的文档。

在takeAction中我们将向智能合约发送两部分内容即:action和dataValue。为了trx处理的方便,我们将使用api.transact() 将发送的内容转为JSON格式。我们从代码中可以看到JSON中主要包含有三部分,账户、action的名字、权限。接下来定义login中的内容:用户名、key。这些信息已经保存在本地了,可以拿来直接使用,现在我们可以用ApiService.login()触发登录操作了。

登录功能实现之后,我们需要通知组件,以方便在登录过程中的调用。我们可以通过把登录消息存储在Redux中来实现,首先让我们来创建三个组件:

  • action
  • reducer
  • store

Action 是把数据从应用传到 store 的有效载荷,它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。action一般都是存储在Redux中的一个普通的JavaScript对象,在本教程中我们只需定义一个action,我们称之为SET_USER,对应到我们上一节内容中的多索引表中存储的数据,在frontend/src/actions/UserAction.js可以找到:

代码语言:javascript
复制
import { ActionTypes } from 'const';

class UserAction {

  static setUser({ name, win_count, lost_count, game }) {
    return {
      type: ActionTypes.SET_USER,
      name,      // 用户名
      win_count, // 用户胜利的次数
      lost_count,// 用户失败的次数
      game,      // 当前游戏信息
    }
  }

}

export default UserAction;

同样的在frontend/src/reducers/UserReducer.js我们可以找到Reducer的相关信息,Action 只是描述了有事情发生了这一事实,并没有指明应用如何更新 state。而这正是 reducer 要做的事情。在 Redux 应用中,所有的 state 都被保存在一个单一对象中。建议在写代码前先想一下这个对象的结构。如何才能以最简的形式把应用的 state 用对象描述出来。在本文中我们在reducer中定义了一个初始化状态和一个状态声明相关内容。当SET_USER action被检测到的时候,我们会用Object.assign()通过创建一个副本的方式去更新初始化的状态。这个函数将会针对store中的每一个用户生成一个新的对象,开发者尽量不要直接修改Redux的store。

代码语言:javascript
复制
import { ActionTypes } from 'const';
//初始化一些信息
const initialState = {
  name: "",
  win_count: 0,
  lost_count: 0,
  game: null,
};

export default function (state = initialState, action) {
  switch (action.type) {
    case ActionTypes.SET_USER: {
      return Object.assign({}, state, {
        name: typeof action.name === "undefined" ? state.name : action.name,
        win_count: action.win_count || initialState.win_count,
        lost_count: action.lost_count || initialState.lost_count,
        game: action.game || initialState.game,
      });
    }
    default:
      return state;
  }
}

本代码中将会使用Redux utility工具combinedReducers导出UserReducer,在frontend/src/reducers/index.js.可以找到,当然我们也可以在以后的开发过程中扩展添加更多的reducer

Store 就是把action和reducer联系到一起的对象。Store 有以下职责:

  • 维持应用的 state;
  • 提供 getState() 方法获取 state;
  • 提供 dispatch(action) 方法更新 state;
  • 通过 subscribe(listener) 注册监听器。

再次强调一下 Redux 应用只有一个单一的 store。当需要拆分处理数据的逻辑时,使用 reducer 组合 而不是创建多个 store。在本文中store的路径为frontend/src/store/index.js。

代码语言:javascript
复制
import { createStore, compose } from 'redux';
import rootReducer from 'reducers';

const initialState = {};
const enhancers = [];

// DevTools Extension for debugging in Chrome
if (process.env.NODE_ENV === 'development') {
  const devToolsExtension = window.devToolsExtension;

  if (typeof devToolsExtension === 'function') {
    enhancers.push(devToolsExtension());
  }
}

const composedEnhancers = compose(
  ...enhancers
)

const store = createStore(
  rootReducer,
  initialState,
  composedEnhancers
)

export default store;

上面介绍了三个组件:action,reducer,store,但并未将三者如何融合的作出说明,当用户点击确认按钮的时候会通过handleSubmit()调用服务组件里的ApiService.login(),然后通过该方法调用智能合约里面的ation。调用智能合约里面的action分为两种情况:

  1. 调用成功:SET_USER这个ation被执行且UserReducer会接收到相应的action,Redux store中将会更新用户名相应的属性值,其他信息不变。
  2. 调用失败:将会记录相应的失败信息到Login登录界面。

为了连接store和web app我们还需要使用connect函数将两者关联起来,可以参看以下代码:

代码语言:javascript
复制
// 将所有的状态信息和组件的属性值放到map表里
const mapStateToProps = state => state;

// 将以下的action和组件的属性值放到map表里
const mapDispatchToProps = {
  setUser: UserAction.setUser,
};

登录界面写好了,我们可以开始写第二个界面即游戏界面了,游戏界面的相关代码不再粘贴在这里,感兴趣的可以仔细阅读Game.jsx。

本文至此,大致介绍了元素战争游戏中是使用什么来开发前端页面的,开发过程中使用到了哪些组件,如何去实现一个service服务,并通过这个服务使前端和智能合约关联起来。具体的代码可以参看源码,也可以看我稍微注释的内容。官方给出的总结如下:

笔者未有过前端开发经验,写作过程中难免有误,还请各位朋友多多指正。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 eosfans 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
区块链
云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档