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
This commit is contained in:
Jaco Greeff 2018-09-14 12:40:35 +02:00 committed by GitHub
parent a5e1fa003d
commit b903f63ff3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 93 deletions

View File

@ -87,6 +87,7 @@ class Creator extends React.PureComponent<Props, State> {
<div className='grow'>
<div className='ui--row'>
<Input
autoFocus
className='full'
isError={!isAddressValid}
label={t('creator.address', {

View File

@ -12,15 +12,11 @@ import Input from '@polkadot/ui-app/Input';
import AddressSummary from '@polkadot/ui-app/AddressSummary';
import InputAddress from '@polkadot/ui-app/InputAddress';
import keyring from '@polkadot/ui-keyring/index';
import addressObservable from '@polkadot/ui-keyring/observable/addresses';
import withObservableBase from '@polkadot/ui-react-rx/with/observableBase';
import Forgetting from './Forgetting';
import translate from './translate';
type Props = I18nProps & {
addressAll?: Array<any>
};
type Props = I18nProps;
type State = {
current: KeyringAddress | null,
@ -93,15 +89,9 @@ class Editor extends React.PureComponent<Props, State> {
}
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<Props, State> {
}
}
export default withObservableBase(
addressObservable.subject, { propName: 'addressAll' }
)(translate(Editor));
export default translate(Editor);

View File

@ -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<any>,
allAddresses?: SubjectInfo,
basePath: string
};
type Actions = 'create' | 'edit';
type State = {
action: Actions
action: Actions,
hidden: Array<string>,
items: Array<TabItem>
};
// FIXME React-router would probably be the best route, not home-grown
@ -35,64 +37,89 @@ const Components: { [index: string]: React.ComponentType<any> } = {
};
class AddressesApp extends React.PureComponent<Props, State> {
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 (
<main className='addresses--App'>
<header>
<Tabs
activeItem={action}
hidden={hidden}
items={items}
onChange={this.onMenuChange}
/>
</header>
<Component onCreateAddress={this.selectEdit} />
<Component onCreateAddress={this.activateEdit} />
</main>
);
}
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));

View File

@ -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<any>) => number;
let hasAddresses: (addressAll?: Array<any>) => boolean;
let hasNoAddresses: (addressAll?: Array<any>) => boolean;
addressesQty = (addressAll?: Array<any>): number =>
hasAddresses(addressAll) && addressAll ? Object.keys(addressAll).length : 0;
hasAddresses = (addressAll?: Array<any>): boolean =>
!hasNoAddresses(addressAll);
hasNoAddresses = (addressAll?: Array<any>): boolean =>
!addressAll || !Object.keys(addressAll).length;
export {
addressesQty,
hasAddresses,
hasNoAddresses
};

View File

@ -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<Item>,
hidden?: Array<string>,
items: Array<TabItem>,
onChange: (name: any) => void
};
@ -34,16 +35,16 @@ export default class Tabs extends React.PureComponent<Props, State> {
};
}
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<Props, State> {
className={classes('ui--Menu', 'ui menu tabular', className)}
style={style}
>
{items.map(({ name, text }) => (
<a
className={classes('item', currentItem === name ? 'active' : '')}
key={name}
onClick={this.onSelect(name)}
>
{text}
</a>
))}
{items
.filter(({ name }) =>
!hidden.includes(name)
)
.map(({ name, text }) => (
<a
className={classes('item', currentItem === name ? 'active' : '')}
key={name}
onClick={this.onSelect(name)}
>
{text}
</a>
))
}
</div>
);
}