国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

剝開比原看代碼17:比原是如何顯示交易的詳細(xì)信息的?

魏明 / 2639人閱讀

摘要:作者比原項(xiàng)目倉庫地址地址在上上篇文章里,我們還剩下一個(gè)小問題沒有解決,即前端是如何顯示一個(gè)交易的詳細(xì)信息的。那我們?cè)诒疚目匆幌拢仍侨绾物@示這個(gè)交易的詳細(xì)信息的。到今天為止,我們終于把比原是如何創(chuàng)建一個(gè)交易的這件事的基本流程弄清楚了。

作者:freewind

比原項(xiàng)目倉庫:

Github地址:https://github.com/Bytom/bytom

Gitee地址:https://gitee.com/BytomBlockc...

在上上篇文章里,我們還剩下一個(gè)小問題沒有解決,即前端是如何顯示一個(gè)交易的詳細(xì)信息的。

先看對(duì)應(yīng)的圖片:


這個(gè)圖片由于太長,分成了兩個(gè),實(shí)際上可以看作一個(gè)。

那么這個(gè)頁面是怎么來的呢?這是在前面以列表的方式顯示交易摘要信息后,可以點(diǎn)擊摘要信息右上角的“查看詳情”鏈接打開。

那我們?cè)诒疚目匆幌拢仍侨绾物@示這個(gè)交易的詳細(xì)信息的。

由于它分成了前后兩端,那么我們跟以前一樣,把它再分成兩個(gè)小問題:

前端是怎么向后臺(tái)發(fā)送請(qǐng)求,并顯示數(shù)據(jù)的

后端是如何拿到相應(yīng)的數(shù)據(jù)發(fā)送給前臺(tái)的

需要說明的是,這個(gè)表格中包含了很多信息,但是我們?cè)诒疚牟⒉淮蛩闳ソ忉尅R驗(yàn)槟芸炊囊豢淳湍苊靼祝床欢木托枰獪?zhǔn)確的了解了比原的核心之后才能解釋清楚,而這一塊等到我們晚點(diǎn)再專門研究。

前端是怎么向后臺(tái)發(fā)送請(qǐng)求,并顯示數(shù)據(jù)的

首先我們看一下顯示交易詳細(xì)信息頁面的路由path是多少。當(dāng)我們把鼠標(biāo)放在交易摘要頁面右上角的“查看詳情”時(shí),會(huì)發(fā)現(xiàn)url類似于:

http://localhost:9888/dashboard/transactions/2d94709749dc59f69cad4d6aea666586d9f7e86b96c9ee81d06f66d4afb5d6dd

其中http://localhost:9888/dashboard/可以看作是這個(gè)應(yīng)用的根路徑,那么路由path應(yīng)該就是/transactions/2d94709749dc59f69cad4d6aea666586d9f7e86b96c9ee81d06f66d4afb5d6dd,后面那么長的顯然是一個(gè)id,所以我們應(yīng)該到代碼中尋找類似于/transactions/:id這樣的字符串,哦,遺憾的是沒有找到。。。

那只能從頭開始了,先找到前端路由的定義:

src/routes.js#L15-L35

// ...
import { routes as transactions } from "features/transactions"

// ...

const makeRoutes = (store) => ({
  path: "/",
  component: Container,
  childRoutes: [
    // ...
    transactions(store),
    // ...
  ]
})

其中的transactions就是我們需要的,而它對(duì)應(yīng)了features/transactions/routes.js

src/features/transactions/routes.js#L1-L21

import { List, New, AssetShow, AssetUpdate } from "./components"
import { makeRoutes } from "features/shared"

export default (store) => {
  return makeRoutes(
    store,
    "transaction",
    List,
    New,
    Show,
    // ...
  )
}

這個(gè)函數(shù)將會(huì)為transactions生成很多相關(guān)的路由路徑。當(dāng)我們把一些組件,比如列表顯示List,新建New,顯示詳情Show等等傳進(jìn)去之后,makeRoutes就會(huì)按照預(yù)先定義好的路徑規(guī)則去添加相關(guān)的path。我們看一下makeRoutes

src/features/shared/routes.js#L1-L44

import { RoutingContainer } from "features/shared/components"
import { humanize } from "utility/string"
import actions from "actions"

const makeRoutes = (store, type, List, New, Show, options = {}) => {
  const loadPage = () => {
    store.dispatch(actions[type].fetchAll())
  }

  const childRoutes = []

  if (New) {
    childRoutes.push({
      path: "create",
      component: New
    })
  }

  if (options.childRoutes) {
    childRoutes.push(...options.childRoutes)
  }

  // 1. 
  if (Show) {
    childRoutes.push({
      path: ":id",
      component: Show
    })
  }

  return {
    // 2.    
    path: options.path || type + "s",
    component: RoutingContainer,
    name: options.name || humanize(type + "s"),
    name_zh: options.name_zh,
    indexRoute: {
      component: List,
      onEnter: (nextState, replace) => {
        loadPage(nextState, replace)
      },
      onChange: (_, nextState, replace) => { loadPage(nextState, replace) }
    },
    childRoutes: childRoutes
  }
}

這段代碼看起來眼熟,因?yàn)槲覀冊(cè)谥把芯坑囝~和交易的列表顯示的時(shí)候,都見過它。而我們今天關(guān)注的是Show,即標(biāo)記為第1處的代碼。

可以看到,當(dāng)傳進(jìn)來了Show組件時(shí),就需要為其生成相關(guān)的路由path。具體是在childRouters中添加一個(gè)path:id,而它本身的路由path是在第2處定義的,默認(rèn)為type + "s",而對(duì)于本例來說,type的值就是transaction,所以Show所對(duì)應(yīng)的完整path就是/transactions/:id,正是我們所需要的。

再回到第1處代碼,可以看到Show組件是從外部傳進(jìn)來的,從前面的函數(shù)可以看到它對(duì)應(yīng)的是src/features/transactions/components/Show.jsx

我們進(jìn)去看一下這個(gè)Show.jsx,首先是定義html組件的函數(shù)render

src/features/transactions/components/Show.jsx#L16-L96

class Show extends BaseShow {

  render() {
    // 1.
    const item = this.props.item
    const lang = this.props.lang
    const btmAmountUnit = this.props.btmAmountUnit

    let view
    if (item) {
      // ..
      view = 
// ... {item.inputs.map((input, index) => )} {item.outputs.map((output, index) => )}
} return this.renderIfFound(view) } }

代碼被我進(jìn)行了大量的簡化,主要是省略了很多數(shù)據(jù)的計(jì)算和一些顯示組件的參數(shù)。我把代碼分成了2部分:

第1處需要注意的是類似于const item = this.props.item這樣的代碼,這里的item就是我們要展示的數(shù)據(jù),對(duì)應(yīng)本文就是一個(gè)transaction對(duì)象,它是從this.props中拿到的,所以我們可以推斷在這個(gè)文件(或者引用的某個(gè)文件)中,會(huì)有一個(gè)connect方法,把store里的數(shù)據(jù)塞過來。一會(huì)兒我們?nèi)タ纯础:竺鎯尚蓄愃凭筒徽f了。

第2處代碼主要就是頁面view的定義了,可以看到里面主要是用到了另一個(gè)自定義組件KeyValueTable。代碼我們就不跟過去了,參照前面的頁面效果我們可以想像出來它就是以表格的形式把一些key-value數(shù)據(jù)顯示出來。

那我們繼續(xù)去尋找connect,很快就在同一個(gè)頁面的后面,找到了如下的定義:

src/features/transactions/components/Show.jsx#L100-L117

import { actions } from "features/transactions"
import { connect } from "react-redux"

const mapStateToProps = (state, ownProps) => ({
  item: state.transaction.items[ownProps.params.id],
  lang: state.core.lang,
  btmAmountUnit: state.core.btmAmountUnit,
  highestBlock: state.core.coreData && state.core.coreData.highestBlock
})

// ...

export default connect(
  mapStateToProps,
  // ...
)(Show)

我只留下了需要關(guān)注的mapStateToProps。可以看到,我們?cè)谇懊娴?處中看到的幾個(gè)變量的賦值,在這里都有定義,其中最重要的item,是從store的當(dāng)前狀態(tài)state中的transaction中的items中取出來的。

那么state.transaction是什么呢?我開始以為它是我們從后臺(tái)取回來的一些數(shù)據(jù),使用transaction這個(gè)名字放到了store里,結(jié)果怎么都搜不到,最后終于發(fā)現(xiàn)原來不是的。

實(shí)際情況是,在我們定義reducer的地方,有一個(gè)makeRootReducer

src/reducers.js#L1-L62

// ...
import { reducers as transaction } from "features/transactions"
// ...

const makeRootReducer = () => (state, action) => {
  // ...
  return combineReducers({
    // ...
    transaction,
    // ...
  })(state, action)
}

原來它是在這里構(gòu)建出來的。首先{ transaction }這種ES6的語法,換成平常的寫法,就是:

{
  transaction: transaction
}

另外,combineReducers這個(gè)方法,是用來把多個(gè)reducer合并起來(可能是因?yàn)閟tore太大,所以把它拆分成多個(gè)reducer管理,每個(gè)reducer只需要處理自己感興趣的部分),并且合并以后,這個(gè)store就會(huì)變成大概這樣:

{
    "transaction": { ... },
    // ...
}

所以前面的state.transaction就是指的這里的{ ... }

那么繼續(xù),在前面的代碼中,可以從state.transaction.items[ownProps.params.id]看到,state.transaction還有一個(gè)items的屬性,它持有的是向后臺(tái)/list-transactions取回的一個(gè)transaction數(shù)組,它又是什么時(shí)候加上去的呢?

這個(gè)問題難倒了我,我花了幾個(gè)小時(shí)搜遍了比原的前后端倉庫,都沒找到,最后只好使出了Chrome的Redux DevTools大法,發(fā)現(xiàn)在一開始的時(shí)候,items就存在了:

在圖上有兩個(gè)紅框,左邊的表示我現(xiàn)在選擇的是初始狀態(tài),右邊顯示最開始transaction就已經(jīng)有了items,于是恍然大悟,這不跟前面是一樣的道理嘛!于是很快找到了定義:

src/features/transactions/reducers.js#L7-L16

export default combineReducers({
  items: reducers.itemsReducer(type),
  queries: reducers.queriesReducer(type),
  generated: (state = [], action) => {
    if (action.type == "GENERATED_TX_HEX") {
      return [action.generated, ...state].slice(0, maxGeneratedHistory)
    }
    return state
  },
})

果然,這里也是用combineReducers把幾個(gè)reducer組合在了一起,所以store里就會(huì)有這里的幾個(gè)key,包括items,以及我們不關(guān)心的queriesgenerated

花了一下午,終于把這塊弄清楚了。看來對(duì)于分析動(dòng)態(tài)語言,一定要腦洞大開,不能預(yù)設(shè)原因,另外要利用各種調(diào)試工具,從不同的角度去查看數(shù)據(jù)。要不是Redux的Chrome插件,我不知道還要卡多久。

我個(gè)人更喜歡靜態(tài)類型的語言,對(duì)于JavaScript這種,除非萬不得以,能躲就躲,主要原因就是代碼中互相引用的線索太少了,很多時(shí)候必須看文檔、代碼甚至去猜,無法利用編輯器提供的跳轉(zhuǎn)功能。

知道了state.transaction.items的來歷以后,后面的事情就好說了。我們是從state.transaction.items[ownProps.params.id]拿到了當(dāng)前需要的transaction,那么state.transaction.items里又是什么時(shí)候放進(jìn)去數(shù)據(jù)的呢?

讓我們?cè)倩氐角懊娴?b>makeRoutes:

src/features/shared/routes.js#L1-L44

// ...
import actions from "actions"

const makeRoutes = (store, type, List, New, Show, options = {}) => {
  // 2.
  const loadPage = () => {
    store.dispatch(actions[type].fetchAll())
  }

  // ...

  return {
    path: options.path || type + "s",
    component: RoutingContainer,
    name: options.name || humanize(type + "s"),
    name_zh: options.name_zh,
    indexRoute: {
      component: List,
      onEnter: (nextState, replace) => {
        loadPage(nextState, replace)
      },
      // 1. 
      onChange: (_, nextState, replace) => { loadPage(nextState, replace) }
    },
    childRoutes: childRoutes
  }
}

在上面的第1處,對(duì)于indexRoute,有一個(gè)onChange的觸發(fā)器。它的意思是,當(dāng)路由的path改變了,并且新的path屬于當(dāng)前的這個(gè)index路由的path(或者子path),后面的函數(shù)將會(huì)觸發(fā)。而后面函數(shù)中的loadPage的定義在第2處代碼,它又會(huì)將actions[type].fetchAll()生成的action進(jìn)行dispatch。由于type在本文中是transaction,通過一步步追蹤(這里稍有點(diǎn)麻煩,不過我們?cè)谥暗奈恼轮幸呀?jīng)走過),我們發(fā)現(xiàn)actions[type].fetchAll對(duì)應(yīng)了src/features/shared/actions/list.js

src/features/shared/actions/list.js#L4-L147

export default function(type, options = {}) {
  const listPath  = options.listPath || `/${type}s`
  const clientApi = () => options.clientApi ? options.clientApi() : chainClient()[`${type}s`]

  // ...

  const fetchAll = () => {
    // ...
  }

  // ...

  return {
    // ...
    fetchAll,
    // ...
  }
}

如果我們還對(duì)這一段代碼有印象的話,就會(huì)知道它最后將會(huì)去訪問后臺(tái)的/list-transactions,并在拿到數(shù)據(jù)后調(diào)用dispatch("RECEIVED_TRANSACTION_ITEMS"),而它將會(huì)被下面的這個(gè)reducer處理:

src/features/shared/reducers.js#L6-L28

export const itemsReducer = (type, idFunc = defaultIdFunc) => (state = {}, action) => {
  if (action.type == `RECEIVED_${type.toUpperCase()}_ITEMS`) {
    // 1.
    const newObjects = {}

    // 2.
    const data = type.toUpperCase() !== "TRANSACTION" ? action.param.data : action.param.data.map(data => ({
      ...data,
      id: data.txId,
      timestamp: data.blockTime,
      blockId: data.blockHash,
      position: data.blockIndex
    }));

    // 3. 
    (data || []).forEach(item => {
      if (!item.id) { item.id = idFunc(item) }
      newObjects[idFunc(item)] = item
    })
    return newObjects
  }
  // ...

  return state
}

依次講解這個(gè)函數(shù)中的三處代碼:

第1處是創(chuàng)建了一個(gè)新的空對(duì)象newObjects,它將在最后替代state.transaction.items,后面會(huì)向它里面賦值

第2處是對(duì)傳進(jìn)來的數(shù)據(jù)進(jìn)行一些處理,如果type是transaction的話,會(huì)把數(shù)組中每個(gè)元素中的某些屬性提升到根下,方便使用

第3處就是把各個(gè)元素放到newObjects中,id為key,對(duì)象本身為value

經(jīng)過這些處理以后,我們才能使用state.transaction.items[ownProps.params.id]拿到合適的transaction對(duì)象,并且由Show.jsx顯示。

前端這塊基本上弄清楚了。我們繼續(xù)看后端

后端是如何拿到相應(yīng)的數(shù)據(jù)發(fā)送給前臺(tái)的

前面我們說過,根據(jù)以往的經(jīng)驗(yàn),我們可以推導(dǎo)出前端會(huì)訪問后端的/list-transactions這個(gè)接口。我們欣喜的發(fā)現(xiàn),這個(gè)接口我們正好在前一篇文章中研究過,這里就可以完全跳過了。

到今天為止,我們終于把“比原是如何創(chuàng)建一個(gè)交易的”這件事的基本流程弄清楚了。雖然還有很多細(xì)節(jié),以及觸及到核心的知道都被忽略了,但是感覺自己對(duì)于比原內(nèi)部的運(yùn)作似乎又多了一些。

也許現(xiàn)在積累的知識(shí)差不多了,該向比原的核心進(jìn)發(fā)了。在下一篇,我將會(huì)嘗試?yán)斫夂头治霰仍暮诵模趯W(xué)習(xí)的過程中,可能會(huì)采用跟目前探索流程分解問題不同的方式。另外,可能前期會(huì)花不少時(shí)間,所以下一篇出來得會(huì)晚一些。當(dāng)然,如果失敗了,說明我目前積累的知識(shí)還是不夠,我還需要再回到當(dāng)前的做法,想辦法再從不同的地方多剝一些比原的外殼,然后再嘗試。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/24175.html

相關(guān)文章

  • 剝開原看代碼16:比原如何通過/list-transactions顯示交易信息

    摘要:前端是如何獲取交易數(shù)據(jù)并顯示出來的我們先在比原的前端代碼庫中尋找。這過程中的推導(dǎo)就不再詳說,需要的話可以看前面講解比原是如何顯示余額的那篇文章。的定義是其中的值是。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 在前一篇文章中,我們...

    hankkin 評(píng)論0 收藏0
  • 剝開原看代碼10:比原如何通過/create-key接口創(chuàng)建密鑰

    摘要:如果傳的是,就會(huì)在內(nèi)部使用默認(rèn)的隨機(jī)數(shù)生成器生成隨機(jī)數(shù)并生成密鑰。使用的是,生成的是一個(gè)形如這樣的全球唯一的隨機(jī)數(shù)把密鑰以文件形式保存在硬盤上。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 在前一篇,我們探討了從瀏覽器的dashb...

    ccj659 評(píng)論0 收藏0
  • 剝開原看代碼06:比原如何把請(qǐng)求區(qū)塊數(shù)據(jù)信息發(fā)出去

    摘要:作者比原項(xiàng)目倉庫地址地址在前一篇中,我們說到,當(dāng)比原向其它節(jié)點(diǎn)請(qǐng)求區(qū)塊數(shù)據(jù)時(shí),會(huì)發(fā)送一個(gè)把需要的區(qū)塊告訴對(duì)方,并把該信息對(duì)應(yīng)的二進(jìn)制數(shù)據(jù)放入對(duì)應(yīng)的通道中,等待發(fā)送。這個(gè)就是真正與連接對(duì)象綁定的一個(gè)緩存區(qū),寫入到它里面的數(shù)據(jù),會(huì)被發(fā)送出去。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https:...

    CloudwiseAPM 評(píng)論0 收藏0
  • 剝開原看代碼12:比原如何通過/create-account-receiver創(chuàng)建地址

    摘要:繼續(xù)看生成地址的方法由于這個(gè)方法里傳過來的是而不是對(duì)象,所以還需要再用查一遍,然后,再調(diào)用這個(gè)私有方法創(chuàng)建地址該方法可以分成部分在第塊中主要關(guān)注的是返回值。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 在比原的dashboard中...

    oneasp 評(píng)論0 收藏0
  • 剝開原看代碼11:比原如何通過接口/create-account創(chuàng)建帳戶

    摘要:而本文將繼續(xù)討論,比原是如何通過接口來創(chuàng)建帳戶的。把各信息打包在一起,稱之為另外,在第處還是一個(gè)需要注意的。比原在代碼中使用它保存各種數(shù)據(jù),比如區(qū)塊帳戶等。到這里,我們已經(jīng)差不多清楚了比原的是如何根據(jù)用戶提交的參數(shù)來創(chuàng)建帳戶的。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https://git...

    haobowd 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

魏明

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<