react前端封装接口弹出错误_Substrate 前端开发-2: 轻松打造你的 React 应用

本文介绍了如何使用Substrate Front-end Template创建React应用,包括连接本地Substrate节点、查询和订阅链上数据、提交交易、管理账户以及处理自定义类型。通过实例展示了如何与Substrate节点交互,提供了一种轻松构建前端应用的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

aab739a7e5e4587251337c4e535b7648.png

用 Substrate Front-end Template 轻松打造你的 React 应用

Substrate 前端开发系列 - 2/2

前言

前端开发系列第一篇講了如何用 Polkadot JS API (簡稱 JS API) 來搭建前端。如果你的前端是用 React 或它家族的框架來寫,那可參考今天要深入討論的另一個官方項目 Substrate Front-end Template。这个项目是官方支持的,它把 JS API 封装好在 [React 应用]里,并对常用的操作进行了封装,放在不同的組件內使用。使你在前端開發中更專注頁面和用戶的互動,省卻一些力量處理㡳層如何和 Substrate 節點交互。

接下来,我们会手把手在本机跑起 Substrate 节点,前端模版。然后查看模版代码是如何查询链上数据,提交交易,最后也说明如何查询链上自定义的数据类型。

连接到本机开发节点

因为我们也需要一个 Substrate 节点,我们会同时 git 克隆一个 Node Template 及 Front-end Template 下来。

mkdir ui-tutorial
cd ui-tutorial

# -- 安装 Rust 及 Substrate
#   更详细的安装指引可参考:
#   https://substrate.dev/docs/en/overview/getting-started
curl https://getsubstrate.io -sSf | bash

# -- 下载 Substrate Node Template,编译并运行起来
git clone https://github.com/substrate-developer-hub/substrate-node-template node-template
cd node-template
# 这指令会编译 Substrate, 须时 30 - 45 分钟不等
cargo build --release
# 运行以下指令会占据整个终端,直到 Cmd+C / Ctrl+C 停止
target/release/node-template --dev

如一切无误,你在终端会看到类似如下的输出:

28931dee5aae82fa9f466fc9d2c3482f.png
Substrate 输出

按下 Ctrl+C / Cmd+C 退出。

要重置本机区块链,则输入:

target/release/node-template purge-chain --dev

接下来安装 Front-end Template:

# -- 安装 NodeJS v12 (https://nodejs.org/en/download/),
#   及 yarn 工具 (https://classic.yarnpkg.com/en/docs/install)

# -- 下载 Substrate 前端模版并跑起来
cd ..
git clone https://github.com/substrate-developer-hub/substrate-front-end-template front-end-template
cd front-end-template
yarn install
yarn start

接着,访问 http://localhost:8000,你会见到以下页面:

8bf44721f50e61f1d657d21cfce5175c.png
01-前端截图

而图中右上方的当下区块生成数也和 Substrate 节点终端所显示的一致 (请确定本机 Substrate 节点在运行着,即上面 target/release/node-template --dev 那句)。如果是这样,那恭喜你,你已成功跑起一个 React 的前端,并成功连接到本机 Substrate 节点上。

如果你打开浏覧器的开发视窗 (Developer Console), 你会注意到一行 console log 说明已连接的远端 socket。

3466cae71a1a58f9969f74b8f8486b5d.png
02-开发视窗

调整远端连接的 Substrate 节点

如果需要调整要连接的终端节点,可打开 src/config/development.json 来指定你的终端。

源码:src/config/development.json

{
  "PROVIDER_SOCKET": "ws://<你的 ws/wss 地址>"
}

SubstrateContext 与 useSubstrate

与 Substrate 节点的交互是封装在 React Context 内, 以 Hook 形式供开发使用. 所以首先我们在主要 <App> 外包一层 Context Provider.

源码:src/App.js

//...
import { SubstrateContextProvider, useSubstrate } from './substrate-lib';
import { DeveloperConsole } from './substrate-lib/components';

//...
function Main() {
  const [accountAddress, setAccountAddress] = useState(null);
  const { apiState, keyring, keyringState } = useSubstrate();
  const accountPair =
    accountAddress &&
    keyringState === 'READY' &&
    keyring.getPair(accountAddress);

  //...
  return (

  )
}
export default function App () {
  return (
    <SubstrateContextProvider>
      <Main />
    </SubstrateContextProvider>
  );
}

<SubstrateContextProvider> 的子组件内,就能用 useSubstrate() 来取得整个 Substrate Context, 当中包含了:

  • socket: 对应现在连接的远端
  • types: Substrate 网络内的自定义结构组
  • keyring: 储存着用户帐号(用户公钥),也开放出接口来为数据和交易签名
  • keyringState: 用户帐号状态,为 [null, 'READY', 'ERROR'] 其中一个
  • api: Polkadot-JS API
  • apiState: Polkadot-JS API 对远端的连接状态,为 [null, 'CONNECTING', 'READY', 'ERROR'] 其中一个

我们检查着 apiStatekeyringState,当它们的值都为 'READY' 时,我们就可以开始读取链上数据。

读取及订阅链上数据 (Queries)

接下来我们会专门讨论 在 Front-end Template 最下面的一个模块 src/TemplateModule.js

2edd7f63c0023decafc00769e99e235a.png
Template Module 模块

这个模块虽然看似简单,但已包含了读取链上数据,提交交易,及监听事件。这前端模块对应着后端 Substrate 节点的一个模块 Template Pallet (查看Pallet 源码)。它有着:

  • 一个存取项 Something
  • 一个读取接口 something
  • 一个外部交易接口 do_something

我们继续看回前端源码。先看介面部份:

源码:src/TemplateModule.js

import { useSubstrate } from './substrate-lib';
import { TxButton } from './substrate-lib/components';

//...

function main (props) {
  //...
  return (
    <Grid.Column>
      <h1>Template Module</h1>
      <Card>
        <Card.Content textAlign='center'>
          <Statistic
            label='Current Value'
            value={currentValue}
          />
        </Card.Content>
      </Card>
      <Form>
        <Form.Field>
          <Input
            type='number'
            id='new_value'
            state='newValue'
            label='New Value'
            onChange={(_, { value }) => setFormValue(value)}
          />
        </Form.Field>
        <Form.Field>
          <TxButton
            accountPair={accountPair}
            label='Store Something'
            setStatus={setStatus}
            type='TRANSACTION'
            attrs={{
              params: [formValue],
              tx: api.tx.templateModule.doSomething
            }}
          />
        </Form.Field>
        <div style={{ overflowWrap: 'break-word' }}>{status}</div>
      </Form>
    </Grid.Column>
  )
}

从上面能看到显示的数值是存在 currentValue (第15行)内,可用 setCurrentValue() 来更改此值。(这是基于 React 的 State Hook。而此 currentValue 的窍门在于它是如何被初始化及修改的。那得跟着看接下来的 useEffect

useEffect(() => {
  let unsubscribe;
  api.query.templateModule.something(newValue => {
    // The storage value is an Option<u32>
    // So we have to check whether it is None first
    // There is also unwrapOr
    if (newValue.isNone) {
      setCurrentValue('<None>');
    } else {
      setCurrentValue(newValue.unwrap().toNumber());
    }
  }).then(unsub => {
    unsubscribe = unsub;
  })
    .catch(console.error);

  return () => unsubscribe && unsubscribe();
}, [api.query.templateModule]);

api 是从 useSubstrate() 取得的 JS API 接口。 api.query.templateModule.something 就是我们从 Substrate 节点处取得数据的方法。而 api query 的用法法则是:

api.query.<pallet_名字>.<pallet 存储名字>(回调函数)

这是对应着 Substrate 后端的 runtime 有个 TemplateModule 为名字的 pallet 模块。而这模块的存储内有个 something() 的读取函数。因为在 node-template 内是如下定义的:

源码: node-template/pallets/template/src/template.rs (以下是 Rust 语法)

// This module's storage items.
decl_storage! {
  trait Store for Module<T: Trait> as TemplateModule {
    Something get(fn something): Option<u32>;
  }
}

JS API 提供两种读取数据的方法。

  1. 一是基于 JS Promise 的方法,可以这样读取数值:javascript const val = await api.query.templateModule.something();
  2. 另一方法,如果想收听该数值,并每次该值在远端作出变更时都收到回调,则用现在 TemplateModule.js 里的写法。源码:src/TemplateModule.jsjavascript let unsubscribe; api.query.templateModule.something(function(val) { // 回调函数 // 在这里设置 UI 里使用的变量。 }).then(unsub => { //取消订阅函数 unsubscribe = unsub; })
    最后把取消函数在 useEffect() 内返回即可。这是 React Effect Hook 的清理方法。

另外值得注意一点是 something 在 Substrate 内是一个 Option<u32> 的格式。因为 Rust 和 Javascript 的数据类型没有一对一映射,因此无符号整数回到 JS 时是以封装的对象呈现。得使用跟着的 .unwrap().toNumber() 来把对象转化回 JS 内的数值。

提交外部交易 (Extrinsics)

接下来看一下这模块是如何提交外部交易,在 Substrate,所有从外部提交的交易都叫 Extrinsics。在这里,我们用一个封装好的组件 <TxButton>

<TxButton
  accountPair={accountPair}
  label='Store Something'
  setStatus={setStatus}
  type='TRANSACTION'
  attrs={{
    params: [formValue],
    tx: api.tx.templateModule.doSomething
  }}
/>

这个组件会生成一个按钮。点击就会向 Substrate 远端发送外部交易。需要以下参数:

  • accountPair: 对交易进行签名的用户帐号(公钥)
  • label:显示在按钮上的文字
  • setStatus:提交交易后的状态更新回调函数
  • type: ['QUERY', 'TRANSACTION'] 其中一个。如果是作写入交易,则选 'TRANSACTION'
  • attrs: 这里传入一个对象: javascript { //外部交易函数 // 这个参看回 `pallet/template/src/lib.rs` 的名字 tx: api.tx.<模块名字>.<extrinsic 名字> //外部交易函数的输入参数数组 params: [...] }
  • style: React 组件的 style
  • disabled: [true, false]。如果是 true,按钮会进入屏闭状态。

用这个组件,基本上能处理大部份点击按钮来触发的外部交易。在下一篇文章,我们会提到如何运用它底层的 JS API 作直接交易。

帐号管理/签署 (Keyring)

keyring 内包含了你的帐号 (也就是你的公钥),以及这帐号签名所需的函数。用 .getPair(), 以一个字符串作输入参数, 取得 accountPair 对象。

const accountPair = keyring.getPair(accountAddress);

然后就以以下方法来签署你的交易:

api.tx.my_pallet.dispatch_call(params).signAndSend(accountPair, 回调函数)

不过这个逻辑已封装在 <TxButton> 内。 如果你是用 <TxButton> 组件来提交外部交易,就不需要顾虑这事了。

收听自定义类型 (Custom Types)

若你要收听的 pallet 内有自定义类型,则在 Substrate 客户端也需要提供这个自定义类型的结构。这自定义结构可放在 src/config/common.json 内。比如:

源码:src/config/common.json

{
  ...,
  "CUSTOM_TYPES": {
    "Price": {
      "dollars": "u32",
      "cents": "u32",
      "currency": "Vec<u8>"
    },
  }
}

u32, Vec<u8>,这些都是 Rust 里的数值类型。上面例子是 Price 结构内分别有 dollars, cents, 及 currency 的栏位。开发者在 Substrate Node Template 代码内怎样定义这结构,也把这结构复制到前端来。

小结

读到这里,我们已经展示了如何利用 Front-end Template 及其封装好的 API 和组件,连接到 Substrate 节点,读取及收听链上数据,提交外部交易,及收听自定义结构数据。

用以上知识,已经足够制作一个简单的前端应用与 Substrate 网络交互。這方面的知識可與我們上一篇用 Polkadot-JS API 與 Substrate 作交互的知識配搭着使用。作起前端開發起來能更得心應手。

本篇读后有什么意见,欢迎在下方留言。对了,如果这篇文章你已读到这里,可能你会有兴趣再知道两个消息:

  • Parity 在亚洲正招聘开发推广及工程师,详情看这里,欢迎报名。
  • 想了解更多 Substrate 开发,来 substrate.dev 查看更多吧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值