您好,登錄后才能下訂單哦!
這篇文章主要講解了“bytom怎么顯示交易的詳細信息”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“bytom怎么顯示交易的詳細信息”吧!
先看對應的圖片:
這個圖片由于太長,分成了兩個,實際上可以看作一個。
那么這個頁面是怎么來的呢?這是在前面以列表的方式顯示交易摘要信息后,可以點擊摘要信息右上角的“查看詳情”鏈接打開。
那我們在本文看一下,比原是如何顯示這個交易的詳細信息的。
由于它分成了前后兩端,那么我們跟以前一樣,把它再分成兩個小問題:
前端是怎么向后臺發送請求,并顯示數據的
后端是如何拿到相應的數據發送給前臺的
需要說明的是,這個表格中包含了很多信息,但是我們在本文并不打算去解釋。因為能看懂的一看就能明白,看不懂的就需要準確的了解了比原的核心之后才能解釋清楚,而這一塊等到我們晚點再專門研究。
首先我們看一下顯示交易詳細信息頁面的路由path是多少。當我們把鼠標放在交易摘要頁面右上角的“查看詳情”時,會發現url類似于:
http://localhost:9888/dashboard/transactions/2d94709749dc59f69cad4d6aea666586d9f7e86b96c9ee81d06f66d4afb5d6dd
其中http://localhost:9888/dashboard/
可以看作是這個應用的根路徑,那么路由path應該就是/transactions/2d94709749dc59f69cad4d6aea666586d9f7e86b96c9ee81d06f66d4afb5d6dd
,后面那么長的顯然是一個id,所以我們應該到代碼中尋找類似于/transactions/:id
這樣的字符串,哦,遺憾的是沒有找到。。。
那只能從頭開始了,先找到前端路由的定義:
src/routes.js#L15-L35
// ... import { routes as transactions } from 'features/transactions' // ... const makeRoutes = (store) => ({ path: '/', component: Container, childRoutes: [ // ... transactions(store), // ... ] })
其中的transactions
就是我們需要的,而它對應了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, // ... ) }
這個函數將會為transactions
生成很多相關的路由路徑。當我們把一些組件,比如列表顯示List
,新建New
,顯示詳情Show
等等傳進去之后,makeRoutes
就會按照預先定義好的路徑規則去添加相關的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 } }
這段代碼看起來眼熟,因為我們在之前研究余額和交易的列表顯示的時候,都見過它。而我們今天關注的是Show
,即標記為第1處的代碼。
可以看到,當傳進來了Show
組件時,就需要為其生成相關的路由path。具體是在childRouters
中添加一個path
為:id
,而它本身的路由path是在第2處定義的,默認為type + 's'
,而對于本例來說,type
的值就是transaction
,所以Show
所對應的完整path就是/transactions/:id
,正是我們所需要的。
再回到第1處代碼,可以看到Show
組件是從外部傳進來的,從前面的函數可以看到它對應的是src/features/transactions/components/Show.jsx
。
我們進去看一下這個Show.jsx
,首先是定義html組件的函數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 = <div> <PageTitle title={title} /> <PageContent> // ... <KeyValueTable title={lang === 'zh' ? '詳情' : 'Details'} items={[ // ... ]} /> {item.inputs.map((input, index) => <KeyValueTable // ... /> )} {item.outputs.map((output, index) => <KeyValueTable // ... /> )} </PageContent> </div> } return this.renderIfFound(view) } }
代碼被我進行了大量的簡化,主要是省略了很多數據的計算和一些顯示組件的參數。我把代碼分成了2部分:
第1處需要注意的是類似于const item = this.props.item
這樣的代碼,這里的item
就是我們要展示的數據,對應本文就是一個transaction
對象,它是從this.props
中拿到的,所以我們可以推斷在這個文件(或者引用的某個文件)中,會有一個connect
方法,把store里的數據塞過來。一會兒我們去看看。后面兩行類似就不說了。
第2處代碼主要就是頁面view的定義了,可以看到里面主要是用到了另一個自定義組件KeyValueTable
。代碼我們就不跟過去了,參照前面的頁面效果我們可以想像出來它就是以表格的形式把一些key-value數據顯示出來。
那我們繼續去尋找connect
,很快就在同一個頁面的后面,找到了如下的定義:
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)
我只留下了需要關注的mapStateToProps
。可以看到,我們在前面第1處中看到的幾個變量的賦值,在這里都有定義,其中最重要的item
,是從store的當前狀態state
中的transaction
中的items
中取出來的。
那么state.transaction
是什么呢?我開始以為它是我們從后臺取回來的一些數據,使用transaction
這個名字放到了store里,結果怎么都搜不到,最后終于發現原來不是的。
實際情況是,在我們定義reducer的地方,有一個makeRootReducer
:
src/reducers.js#L1-L62
// ... import { reducers as transaction } from 'features/transactions' // ... const makeRootReducer = () => (state, action) => { // ... return combineReducers({ // ... transaction, // ... })(state, action) }
原來它是在這里構建出來的。首先{ transaction }
這種ES6的語法,換成平常的寫法,就是:
{ transaction: transaction }
另外,combineReducers
這個方法,是用來把多個reducer合并起來(可能是因為store太大,所以把它拆分成多個reducer管理,每個reducer只需要處理自己感興趣的部分),并且合并以后,這個store就會變成大概這樣:
{ "transaction": { ... }, // ... }
所以前面的state.transaction
就是指的這里的{ ... }
。
那么繼續,在前面的代碼中,可以從state.transaction.items[ownProps.params.id]
看到,state.transaction
還有一個items
的屬性,它持有的是向后臺/list-transactions
取回的一個transaction數組,它又是什么時候加上去的呢?
這個問題難倒了我,我花了幾個小時搜遍了比原的前后端倉庫,都沒找到,最后只好使出了Chrome的Redux DevTools大法,發現在一開始的時候,items
就存在了:
在圖上有兩個紅框,左邊的表示我現在選擇的是初始狀態,右邊顯示最開始transaction
就已經有了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
把幾個reducer組合在了一起,所以store里就會有這里的幾個key,包括items
,以及我們不關心的queries
和generated
。
花了一下午,終于把這塊弄清楚了。看來對于分析動態語言,一定要腦洞大開,不能預設原因,另外要利用各種調試工具,從不同的角度去查看數據。要不是Redux的Chrome插件,我不知道還要卡多久。
我個人更喜歡靜態類型的語言,對于JavaScript這種,除非萬不得以,能躲就躲,主要原因就是代碼中互相引用的線索太少了,很多時候必須看文檔、代碼甚至去猜,無法利用編輯器提供的跳轉功能。
知道了state.transaction.items
的來歷以后,后面的事情就好說了。我們是從state.transaction.items[ownProps.params.id]
拿到了當前需要的transaction,那么state.transaction.items
里又是什么時候放進去數據的呢?
讓我們再回到前面的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處,對于indexRoute
,有一個onChange
的觸發器。它的意思是,當路由的path改變了,并且新的path屬于當前的這個index路由的path(或者子path),后面的函數將會觸發。而后面函數中的loadPage
的定義在第2處代碼,它又會將actions[type].fetchAll()
生成的action進行dispatch。由于type
在本文中是transaction
,通過一步步追蹤(這里稍有點麻煩,不過我們在之前的文章中已經走過),我們發現actions[type].fetchAll
對應了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, // ... } }
如果我們還對這一段代碼有印象的話,就會知道它最后將會去訪問后臺的/list-transactions
,并在拿到數據后調用dispatch("RECEIVED_TRANSACTION_ITEMS")
,而它將會被下面的這個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 }
依次講解這個函數中的三處代碼:
第1處是創建了一個新的空對象newObjects
,它將在最后替代state.transaction.items
,后面會向它里面賦值
第2處是對傳進來的數據進行一些處理,如果type是transaction
的話,會把數組中每個元素中的某些屬性提升到根下,方便使用
第3處就是把各個元素放到newObjects
中,id
為key,對象本身為value
經過這些處理以后,我們才能使用state.transaction.items[ownProps.params.id]
拿到合適的transaction對象,并且由Show.jsx
顯示。
前端這塊基本上弄清楚了。我們繼續看后端
前面我們說過,根據以往的經驗,我們可以推導出前端會訪問后端的/list-transactions
這個接口。我們欣喜的發現,這個接口我們正好在前一篇文章中研究過,這里就可以完全跳過了。
感謝各位的閱讀,以上就是“bytom怎么顯示交易的詳細信息”的內容了,經過本文的學習后,相信大家對bytom怎么顯示交易的詳細信息這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。