From 35fdbf335270d67e7c2e02949c35078e650c906d Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 21 Nov 2016 15:45:58 +0100 Subject: [PATCH] Progressive Accounts List Rendering #3240 --- js/src/views/Accounts/Summary/summary.js | 39 +++++++++++++-- js/src/views/Accounts/accounts.css | 22 ++++++++ js/src/views/Accounts/accounts.js | 64 ++++++++++++++++++------ 3 files changed, 106 insertions(+), 19 deletions(-) diff --git a/js/src/views/Accounts/Summary/summary.js b/js/src/views/Accounts/Summary/summary.js index 5a96f64ff..88249bb1c 100644 --- a/js/src/views/Accounts/Summary/summary.js +++ b/js/src/views/Accounts/Summary/summary.js @@ -16,6 +16,7 @@ import React, { Component, PropTypes } from 'react'; import { Link } from 'react-router'; +import { isEqual } from 'lodash'; import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags, Input } from '../../../ui'; @@ -30,7 +31,6 @@ export default class Summary extends Component { link: PropTypes.string, name: PropTypes.string, noLink: PropTypes.bool, - children: PropTypes.node, handleAddSearchToken: PropTypes.func }; @@ -42,8 +42,42 @@ export default class Summary extends Component { name: 'Unnamed' }; + shouldComponentUpdate (nextProps) { + const prev = { + link: this.props.link, name: this.props.name, + noLink: this.props.noLink, + meta: this.props.account.meta, address: this.props.account.address + }; + + const next = { + link: nextProps.link, name: nextProps.name, + noLink: nextProps.noLink, + meta: nextProps.account.meta, address: nextProps.account.address + }; + + if (!isEqual(next, prev)) { + return true; + } + + const prevTokens = this.props.balance.tokens || []; + const nextTokens = nextProps.balance.tokens || []; + + if (prevTokens.length !== nextTokens.length) { + return true; + } + + const prevValues = prevTokens.map((t) => t.value.toNumber()); + const nextValues = nextTokens.map((t) => t.value.toNumber()); + + if (!isEqual(prevValues, nextValues)) { + return true; + } + + return false; + } + render () { - const { account, children, handleAddSearchToken } = this.props; + const { account, handleAddSearchToken } = this.props; const { tags } = account.meta; if (!account) { @@ -71,7 +105,6 @@ export default class Summary extends Component { byline={ addressComponent } /> { this.renderBalance() } - { children } ); } diff --git a/js/src/views/Accounts/accounts.css b/js/src/views/Accounts/accounts.css index f98a09ea3..0ed8b5256 100644 --- a/js/src/views/Accounts/accounts.css +++ b/js/src/views/Accounts/accounts.css @@ -30,3 +30,25 @@ right: 1em; top: 4em; } + +.loadings { + display: flex; + flex-wrap: wrap; + + .loading { + flex: 0 1 50%; + width: 50%; + height: 150px; + display: flex; + padding: 0.25em; + box-sizing: border-box; + + > div { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + background-color: rgba(0, 0, 0, 0.8); + } + } +} diff --git a/js/src/views/Accounts/accounts.js b/js/src/views/Accounts/accounts.js index 0e7cd0500..24909703b 100644 --- a/js/src/views/Accounts/accounts.js +++ b/js/src/views/Accounts/accounts.js @@ -38,37 +38,69 @@ class Accounts extends Component { } state = { + accountsNodes: null, addressBook: false, newDialog: false, sortOrder: '', searchValues: [], - searchTokens: [] + searchTokens: [], + show: false + } + + componentDidMount () { + window.setTimeout(() => { + const accountsNodes = this.renderAccounts(); + this.setState({ show: true, accountsNodes }); + }, 0); } render () { - const { accounts, hasAccounts, balances } = this.props; - const { searchValues, sortOrder } = this.state; - return (
{ this.renderNewDialog() } { this.renderActionbar() } - - - - + + { this.state.show ? this.state.accountsNodes : this.renderLoading() }
); } + renderLoading () { + const { accounts } = this.props; + + const loadings = ((accounts && Object.keys(accounts)) || []).map((_, idx) => ( +
+
+
+ )); + + return ( +
+ { loadings } +
+ ); + } + + renderAccounts () { + const { accounts, hasAccounts, balances } = this.props; + const { searchValues, sortOrder } = this.state; + + return ( + + + + + ); + } + renderSearchButton () { const onChange = (searchTokens, searchValues) => { this.setState({ searchTokens, searchValues });