From 52ab9ac0e33df71af2335632f30435009f808ea4 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 3 Sep 2019 10:19:50 +0200 Subject: [PATCH] withApi -> useContext (fixes ref issues) (#1576) --- packages/app-explorer/src/NodeInfo/index.tsx | 119 +++++++----------- packages/apps/src/SideBar/NodeInfo.tsx | 69 +++++----- packages/apps/src/overlays/Connecting.tsx | 28 ++--- packages/react-components/src/AddressCard.tsx | 5 +- .../react-components/src/LinkPolkascan.tsx | 18 ++- 5 files changed, 95 insertions(+), 144 deletions(-) diff --git a/packages/app-explorer/src/NodeInfo/index.tsx b/packages/app-explorer/src/NodeInfo/index.tsx index 595e29226a..778c27ba99 100644 --- a/packages/app-explorer/src/NodeInfo/index.tsx +++ b/packages/app-explorer/src/NodeInfo/index.tsx @@ -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 { + const { api } = useContext(ApiContext); + const [info, setInfo] = useState>({}); + const [nextRefresh, setNextRefresh] = useState(Date.now()); + const [timerId, setTimerId] = useState(0); -class App extends React.PureComponent { - 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 ( - <> - - - - - ); - } - - 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 => { - const { api } = this.props; - + const getStatus = async (): Promise => { try { const [blockNumber, health, peers, extrinsics] = await Promise.all([ api.derive.chain.bestNumber(), @@ -95,15 +40,37 @@ class App extends React.PureComponent { api.rpc.author.pendingExtrinsics>() ]); - 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 ( + <> + + + + + ); } -export default withMulti( - App, - translate, - withApi -); +export default translate(NodeInfo); diff --git a/packages/apps/src/SideBar/NodeInfo.tsx b/packages/apps/src/SideBar/NodeInfo.tsx index 2cce89069e..fb5017a5bc 100644 --- a/packages/apps/src/SideBar/NodeInfo.tsx +++ b/packages/apps/src/SideBar/NodeInfo.tsx @@ -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 ( -
-   - -
- ); -} - -function NodeInfo (props: Props): React.ReactElement { - const { api, className } = props; +function NodeInfo ({ className }: Props): React.ReactElement { + const { api, isApiReady } = useContext(ApiContext); return (
- {renderNode(props)} + {isApiReady && ( +
+   + +
+ )}
{api.libraryInfo.replace('@polkadot/', '')}
{uiInfo}
); } -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; + } +`; diff --git a/packages/apps/src/overlays/Connecting.tsx b/packages/apps/src/overlays/Connecting.tsx index 0c3a2ac7ef..5eef717f45 100644 --- a/packages/apps/src/overlays/Connecting.tsx +++ b/packages/apps/src/overlays/Connecting.tsx @@ -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 | 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 | null { if (isApiConnected) { return null; } @@ -61,20 +61,16 @@ function renderConnecting ({ className, isApiConnected, t }: Props): React.React ); } -function Connecting (props: Props): React.ReactElement { - return ( - <> - {renderExtension(props) || renderConnecting(props)} - - ); +function Connecting (props: Props): React.ReactElement | null { + const api = useContext(ApiContext); + + return || ; } -export default withMulti( +export default translate( styled(Connecting)` background: #ffe6e6; border-color: #c00; color: #4d0000; - `, - translate, - withApi + ` ); diff --git a/packages/react-components/src/AddressCard.tsx b/packages/react-components/src/AddressCard.tsx index 73409a2399..fba31aefa8 100644 --- a/packages/react-components/src/AddressCard.tsx +++ b/packages/react-components/src/AddressCard.tsx @@ -28,11 +28,12 @@ function AddressCard (props: Props): React.ReactElement { {...props} className='ui--AddressCard-AddressRow' /> - {withExplorer && ( + {withExplorer && value && (
)} diff --git a/packages/react-components/src/LinkPolkascan.tsx b/packages/react-components/src/LinkPolkascan.tsx index 1c2aed7448..60378da83c 100644 --- a/packages/react-components/src/LinkPolkascan.tsx +++ b/packages/react-components/src/LinkPolkascan.tsx @@ -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 = { extrinsic: '/system/extrinsic/' }; -function LinkPolkascan ({ className, currentChain, data, t, type }: Props): React.ReactElement | null { +function LinkPolkascan ({ className, data, t, type }: Props): React.ReactElement | 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 + ` );