From b903f63ff3d8e37e86016bc71733f62985528d7b Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 14 Sep 2018 12:40:35 +0200 Subject: [PATCH] Fix Address add flicker (#309) * Fix Address add flicker * Clenaup unused * use getDerivedState in Tabs * Mark functions private * Creator autoFocus on Input * No extra {} on proptype --- packages/app-addresses/src/Creator.tsx | 1 + packages/app-addresses/src/Editor.tsx | 18 +--- packages/app-addresses/src/index.tsx | 99 +++++++++++++------- packages/app-addresses/src/util/addresses.ts | 24 ----- packages/ui-app/src/Tabs.tsx | 42 +++++---- 5 files changed, 91 insertions(+), 93 deletions(-) delete mode 100644 packages/app-addresses/src/util/addresses.ts diff --git a/packages/app-addresses/src/Creator.tsx b/packages/app-addresses/src/Creator.tsx index 9ddcefc82a..b515837d52 100644 --- a/packages/app-addresses/src/Creator.tsx +++ b/packages/app-addresses/src/Creator.tsx @@ -87,6 +87,7 @@ class Creator extends React.PureComponent {
-}; +type Props = I18nProps; type State = { current: KeyringAddress | null, @@ -93,15 +89,9 @@ class Editor extends React.PureComponent { } renderData () { - const { addressAll, t } = this.props; + const { t } = this.props; const { current, editedName } = this.state; - if (!addressAll || !Object.keys(addressAll).length) { - return t('editor.none', { - defaultValue: 'There are no saved addresses. Add some first.' - }); - } - const address = current ? current.address() : undefined; @@ -245,6 +235,4 @@ class Editor extends React.PureComponent { } } -export default withObservableBase( - addressObservable.subject, { propName: 'addressAll' } -)(translate(Editor)); +export default translate(Editor); diff --git a/packages/app-addresses/src/index.tsx b/packages/app-addresses/src/index.tsx index 9943bdbc7e..1f9e97b3a3 100644 --- a/packages/app-addresses/src/index.tsx +++ b/packages/app-addresses/src/index.tsx @@ -3,29 +3,31 @@ // of the ISC license. See the LICENSE file for details. import { I18nProps } from '@polkadot/ui-app/types'; +import { SubjectInfo } from '@polkadot/ui-keyring/observable/types'; import './index.css'; import React from 'react'; import addressObservable from '@polkadot/ui-keyring/observable/addresses'; -import Tabs from '@polkadot/ui-app/Tabs'; +import Tabs, { TabItem } from '@polkadot/ui-app/Tabs'; import withObservableBase from '@polkadot/ui-react-rx/with/observableBase'; -import { hasNoAddresses } from './util/addresses'; import Creator from './Creator'; import Editor from './Editor'; import translate from './translate'; type Props = I18nProps & { - addressAll?: Array, + allAddresses?: SubjectInfo, basePath: string }; type Actions = 'create' | 'edit'; type State = { - action: Actions + action: Actions, + hidden: Array, + items: Array }; // FIXME React-router would probably be the best route, not home-grown @@ -35,64 +37,89 @@ const Components: { [index: string]: React.ComponentType } = { }; class AddressesApp extends React.PureComponent { - state: State = { action: 'edit' }; + state: State; - componentDidUpdate () { - const { addressAll } = this.props; - const { action } = this.state; + constructor (props: Props) { + super(props); - if (action === 'edit' && hasNoAddresses(addressAll)) { - this.selectCreate(); + const { allAddresses = {}, t } = props; + const baseState = Object.keys(allAddresses).length !== 0 + ? AddressesApp.showEditState() + : AddressesApp.hideEditState(); + + this.state = { + ...baseState, + items: [ + { + name: 'edit', + text: t('app.edit', { defaultValue: 'Edit address' }) + }, + { + name: 'create', + text: t('app.create', { defaultValue: 'Add address' }) + } + ] + }; + } + + static showEditState () { + return { + action: 'edit' as Actions, + hidden: [] + }; + } + + static hideEditState () { + return { + action: 'create' as Actions, + hidden: ['edit'] + }; + } + + static getDerivedStateFromProps ({ allAddresses = {} }: Props, { hidden }: State) { + const hasAddresses = Object.keys(allAddresses).length !== 0; + + if (hidden.length === 0) { + return hasAddresses + ? null + : AddressesApp.hideEditState(); } + + return hasAddresses + ? AddressesApp.showEditState() + : null; } render () { - const { addressAll, t } = this.props; - const { action } = this.state; + const { action, hidden, items } = this.state; const Component = Components[action]; - const items = [ - { - name: 'edit', - text: t('app.edit', { defaultValue: 'Edit address' }) - }, - { - name: 'create', - text: t('app.create', { defaultValue: 'Add address' }) - } - ]; - - // Do not load Editor tab if no addresses - if (hasNoAddresses(addressAll)) { - items.splice(0, 1); - } return (
- +
); } - onMenuChange = (action: Actions) => { + private onMenuChange = (action: Actions) => { this.setState({ action }); } - selectCreate = (): void => { - this.setState({ action: 'create' }); - } - - selectEdit = (): void => { - this.setState({ action: 'edit' }); + private activateEdit = (): void => { + this.setState( + AddressesApp.showEditState() + ); } } export default withObservableBase( - addressObservable.subject, { propName: 'addressAll' } + addressObservable.subject, { propName: 'allAddresses' } )(translate(AddressesApp)); diff --git a/packages/app-addresses/src/util/addresses.ts b/packages/app-addresses/src/util/addresses.ts deleted file mode 100644 index c9507465b6..0000000000 --- a/packages/app-addresses/src/util/addresses.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2017-2018 @polkadot/app-accounts authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -let addressesQty: (addressAll?: Array) => number; - -let hasAddresses: (addressAll?: Array) => boolean; - -let hasNoAddresses: (addressAll?: Array) => boolean; - -addressesQty = (addressAll?: Array): number => - hasAddresses(addressAll) && addressAll ? Object.keys(addressAll).length : 0; - -hasAddresses = (addressAll?: Array): boolean => - !hasNoAddresses(addressAll); - -hasNoAddresses = (addressAll?: Array): boolean => - !addressAll || !Object.keys(addressAll).length; - -export { - addressesQty, - hasAddresses, - hasNoAddresses -}; diff --git a/packages/ui-app/src/Tabs.tsx b/packages/ui-app/src/Tabs.tsx index 5f14d6bae9..cf4cf9626f 100644 --- a/packages/ui-app/src/Tabs.tsx +++ b/packages/ui-app/src/Tabs.tsx @@ -8,14 +8,15 @@ import React from 'react'; import classes from './util/classes'; -type Item = { +export type TabItem = { name: string, text: React.ReactNode }; type Props = BareProps & { activeItem: string, - items: Array, + hidden?: Array, + items: Array, onChange: (name: any) => void }; @@ -34,16 +35,16 @@ export default class Tabs extends React.PureComponent { }; } - componentDidUpdate (prevProps: Props, prevState: State) { - const { activeItem } = this.props; - - if (activeItem !== prevState.active) { - this.setState({ active: activeItem }); - } + static getDerivedStateFromProps ({ activeItem }: Props, { active }: State) { + return activeItem === active + ? null + : { + active: activeItem + }; } render () { - const { className, activeItem, items, style } = this.props; + const { className, activeItem, hidden = [], items, style } = this.props; const { active } = this.state; const currentItem = active || activeItem; @@ -52,15 +53,20 @@ export default class Tabs extends React.PureComponent { className={classes('ui--Menu', 'ui menu tabular', className)} style={style} > - {items.map(({ name, text }) => ( - - {text} - - ))} + {items + .filter(({ name }) => + !hidden.includes(name) + ) + .map(({ name, text }) => ( + + {text} + + )) + }
); }