withApi -> useContext (fixes ref issues) (#1576)

This commit is contained in:
Jaco Greeff 2019-09-03 10:19:50 +02:00 committed by GitHub
parent 596615a51c
commit 52ab9ac0e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 144 deletions

View File

@ -3,12 +3,11 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { Health, PeerInfo, Extrinsic } from '@polkadot/types/interfaces';
import { ApiProps } from '@polkadot/react-api/types';
import { AppProps, I18nProps } from '@polkadot/react-components/types';
import { I18nProps } from '@polkadot/react-components/types';
import { Info } from './types';
import React from 'react';
import { withApi, withMulti } from '@polkadot/react-api';
import React, { useContext, useEffect, useState } from 'react';
import { ApiContext } from '@polkadot/react-api';
import { Vec } from '@polkadot/types';
import './index.css';
@ -20,73 +19,19 @@ import translate from './translate';
const POLL_TIMEOUT = 9900;
type Props = ApiProps & AppProps & I18nProps;
type Props = I18nProps;
interface State {
info?: Info;
nextRefresh: number;
timerId?: number;
}
function NodeInfo ({ t }: Props): React.ReactElement<Props> {
const { api } = useContext(ApiContext);
const [info, setInfo] = useState<Partial<Info>>({});
const [nextRefresh, setNextRefresh] = useState(Date.now());
const [timerId, setTimerId] = useState(0);
class App extends React.PureComponent<Props, State> {
private isActive = true;
public state: State = {
nextRefresh: Date.now()
const executeStatus = (): void => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
getStatus().catch((): void => {});
};
public componentDidMount (): void {
this.getStatus().catch((): void => {
// ignore
});
}
public componentWillUnmount (): void {
const { timerId } = this.state;
this.isActive = false;
if (timerId) {
window.clearTimeout(timerId);
}
}
public render (): React.ReactNode {
const { t } = this.props;
const { info = {}, nextRefresh } = this.state;
return (
<>
<Summary
info={info}
nextRefresh={nextRefresh}
/>
<Peers peers={info.peers} />
<Extrinsics
blockNumber={info.blockNumber}
label={t('pending extrinsics')}
value={info.extrinsics}
/>
</>
);
}
private setInfo (info?: Info): void {
if (!this.isActive) {
return;
}
this.setState({
info,
nextRefresh: (Date.now() + POLL_TIMEOUT),
// eslint-disable-next-line @typescript-eslint/no-misused-promises
timerId: window.setTimeout(this.getStatus, POLL_TIMEOUT)
});
}
private getStatus = async (): Promise<void> => {
const { api } = this.props;
const getStatus = async (): Promise<void> => {
try {
const [blockNumber, health, peers, extrinsics] = await Promise.all([
api.derive.chain.bestNumber(),
@ -95,15 +40,37 @@ class App extends React.PureComponent<Props, State> {
api.rpc.author.pendingExtrinsics<Vec<Extrinsic>>()
]);
this.setInfo({ blockNumber, extrinsics, health, peers });
setInfo({ blockNumber, extrinsics, health, peers });
} catch (error) {
this.setInfo();
setInfo({});
}
}
setNextRefresh(Date.now() + POLL_TIMEOUT);
setTimerId(window.setTimeout(executeStatus, POLL_TIMEOUT));
};
useEffect((): () => void => {
executeStatus();
return (): void => {
window.clearTimeout(timerId);
};
}, []);
return (
<>
<Summary
info={info}
nextRefresh={nextRefresh}
/>
<Peers peers={info.peers} />
<Extrinsics
blockNumber={info.blockNumber}
label={t('pending extrinsics')}
value={info.extrinsics}
/>
</>
);
}
export default withMulti(
App,
translate,
withApi
);
export default translate(NodeInfo);

View File

@ -2,68 +2,57 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiProps } from '@polkadot/react-api/types';
import { BareProps } from '@polkadot/react-components/types';
import React from 'react';
import React, { useContext } from 'react';
import styled from 'styled-components';
import { withApi } from '@polkadot/react-api/with';
import { ApiContext } from '@polkadot/react-api';
import { NodeName, NodeVersion } from '@polkadot/react-query';
interface Props extends ApiProps, BareProps {}
type Props = BareProps;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const pkgJson = require('../../package.json');
const uiInfo = `apps v${pkgJson.version}`;
function renderNode ({ isApiReady }: Props): React.ReactNode {
if (!isApiReady) {
return null;
}
return (
<div>
<NodeName />&nbsp;
<NodeVersion label='v' />
</div>
);
}
function NodeInfo (props: Props): React.ReactElement<Props> {
const { api, className } = props;
function NodeInfo ({ className }: Props): React.ReactElement<Props> {
const { api, isApiReady } = useContext(ApiContext);
return (
<div className={className}>
{renderNode(props)}
{isApiReady && (
<div>
<NodeName />&nbsp;
<NodeVersion label='v' />
</div>
)}
<div>{api.libraryInfo.replace('@polkadot/', '')}</div>
<div>{uiInfo}</div>
</div>
);
}
export default withApi(
styled(NodeInfo)`
background: transparent;
color: white;
font-size: 0.75rem;
opacity: 0.5;
padding: 0 1.5rem 0 1.5rem;
text-align: right;
export default styled(NodeInfo)`
background: transparent;
color: white;
font-size: 0.75rem;
opacity: 0.5;
padding: 0 1.5rem 0 1.5rem;
text-align: right;
> div {
margin-bottom: -0.125em;
> div {
margin-bottom: -0.125em;
> div {
display: inline-block;
}
&.spacer {
margin-bottom: 0.5rem;
}
display: inline-block;
}
.rx--updated {
background: inherit !important;
&.spacer {
margin-bottom: 0.5rem;
}
`
);
}
.rx--updated {
background: inherit !important;
}
`;

View File

@ -2,18 +2,18 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { I18nProps } from '@polkadot/react-components/types';
import { ApiProps } from '@polkadot/react-api/types';
import { I18nProps } from '@polkadot/react-components/types';
import React from 'react';
import React, { useContext } from 'react';
import styled from 'styled-components';
import { withApi, withMulti } from '@polkadot/react-api';
import { ApiContext } from '@polkadot/react-api';
import settings from '@polkadot/ui-settings';
import translate from '../translate';
import BaseOverlay from './Base';
type Props = I18nProps & ApiProps;
type Props = I18nProps;
const isFirefox = typeof (window as any).InstallTrigger !== 'undefined';
const wsUrl = settings.apiUrl;
@ -21,7 +21,7 @@ const isWs = wsUrl.startsWith('ws://');
const isWsRemote = wsUrl.includes('127.0.0.1');
const isHttps = window.location.protocol.startsWith('https:');
function renderExtension ({ className, isWaitingInjected, t }: Props): React.ReactNode {
function ExtensionOverlay ({ className, isWaitingInjected, t }: ApiProps & Props): React.ReactElement<Props> | null {
if (!isWaitingInjected) {
return null;
}
@ -36,7 +36,7 @@ function renderExtension ({ className, isWaitingInjected, t }: Props): React.Rea
);
}
function renderConnecting ({ className, isApiConnected, t }: Props): React.ReactNode {
function ConnectOverlay ({ className, isApiConnected, t }: ApiProps & Props): React.ReactElement<Props> | null {
if (isApiConnected) {
return null;
}
@ -61,20 +61,16 @@ function renderConnecting ({ className, isApiConnected, t }: Props): React.React
);
}
function Connecting (props: Props): React.ReactElement<Props> {
return (
<>
{renderExtension(props) || renderConnecting(props)}
</>
);
function Connecting (props: Props): React.ReactElement<Props> | null {
const api = useContext(ApiContext);
return <ExtensionOverlay {...props} {...api} /> || <ConnectOverlay {...props} {...api} />;
}
export default withMulti(
export default translate(
styled(Connecting)`
background: #ffe6e6;
border-color: #c00;
color: #4d0000;
`,
translate,
withApi
`
);

View File

@ -28,11 +28,12 @@ function AddressCard (props: Props): React.ReactElement<Props> {
{...props}
className='ui--AddressCard-AddressRow'
/>
{withExplorer && (
{withExplorer && value && (
<div className='ui--AddressCard-explorer'>
<LinkPolkascan
className='ui--AddressCard-exporer-link'
data={value}
data={value.toString()}
type='address'
/>
</div>
)}

View File

@ -2,22 +2,21 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiProps } from '@polkadot/react-api/types';
import { I18nProps } from './types';
import React from 'react';
import React, { useContext } from 'react';
import styled from 'styled-components';
import { withApi, withMulti } from '@polkadot/react-api';
import { ApiContext } from '@polkadot/react-api';
import translate from './translate';
export type LinkTypes = 'address' | 'block' | 'extrinsic';
type Props = ApiProps & I18nProps & {
interface Props extends I18nProps {
className?: string;
data: string;
type: LinkTypes;
};
}
const BASE = 'https://polkascan.io/pre/';
@ -33,7 +32,8 @@ const TYPES: Record<string, string> = {
extrinsic: '/system/extrinsic/'
};
function LinkPolkascan ({ className, currentChain, data, t, type }: Props): React.ReactElement<Props> | null {
function LinkPolkascan ({ className, data, t, type }: Props): React.ReactElement<Props> | null {
const { currentChain } = useContext(ApiContext);
const extChain = CHAINS[currentChain];
const extType = TYPES[type];
@ -54,11 +54,9 @@ function LinkPolkascan ({ className, currentChain, data, t, type }: Props): Reac
);
}
export default withMulti(
export default translate(
styled(LinkPolkascan)`
margin-top: 1rem;
text-align: right;
`,
translate,
withApi
`
);