瀏覽代碼

Introduce React.memo for react-components (#2404)

* Introduce React.memo for react-components

* Api with memo

* Cleanup Dropdown

* Adjust toggle highlight

* Chart exports
Jaco Greeff 5 年之前
父節點
當前提交
15c6b90b6a
共有 59 個文件被更改,包括 269 次插入134 次删除
  1. 3 1
      packages/react-api/src/Api.tsx
  2. 3 1
      packages/react-components/src/AccountNameJudgement.tsx
  3. 3 1
      packages/react-components/src/Available.tsx
  4. 3 1
      packages/react-components/src/Balance.tsx
  5. 3 1
      packages/react-components/src/Bonded.tsx
  6. 3 1
      packages/react-components/src/Button/Button.tsx
  7. 3 1
      packages/react-components/src/Button/Divider.tsx
  8. 3 1
      packages/react-components/src/Button/Or.tsx
  9. 3 2
      packages/react-components/src/ButtonCancel.tsx
  10. 4 6
      packages/react-components/src/Chart/Base.tsx
  11. 4 14
      packages/react-components/src/Chart/Doughnut.tsx
  12. 5 19
      packages/react-components/src/Chart/HorizBar.tsx
  13. 4 9
      packages/react-components/src/Chart/Line.tsx
  14. 3 1
      packages/react-components/src/Chart/index.ts
  15. 44 0
      packages/react-components/src/Chart/types.ts
  16. 3 1
      packages/react-components/src/CryptoType.tsx
  17. 23 18
      packages/react-components/src/Dropdown.tsx
  18. 3 1
      packages/react-components/src/Event.tsx
  19. 12 7
      packages/react-components/src/Expander.tsx
  20. 3 1
      packages/react-components/src/Extrinsic.tsx
  21. 3 1
      packages/react-components/src/Input.tsx
  22. 3 1
      packages/react-components/src/InputConsts/SelectKey.tsx
  23. 3 1
      packages/react-components/src/InputConsts/SelectSection.tsx
  24. 3 1
      packages/react-components/src/InputConsts/index.tsx
  25. 3 1
      packages/react-components/src/InputError.tsx
  26. 3 1
      packages/react-components/src/InputExtrinsic/SelectMethod.tsx
  27. 3 1
      packages/react-components/src/InputExtrinsic/SelectSection.tsx
  28. 3 1
      packages/react-components/src/InputExtrinsic/index.tsx
  29. 3 1
      packages/react-components/src/InputNumber.tsx
  30. 3 1
      packages/react-components/src/InputRpc/SelectMethod.tsx
  31. 3 1
      packages/react-components/src/InputRpc/SelectSection.tsx
  32. 3 1
      packages/react-components/src/InputRpc/index.tsx
  33. 3 1
      packages/react-components/src/InputStorage/SelectKey.tsx
  34. 3 1
      packages/react-components/src/InputStorage/SelectSection.tsx
  35. 3 1
      packages/react-components/src/InputStorage/index.tsx
  36. 3 1
      packages/react-components/src/InputTags.tsx
  37. 3 1
      packages/react-components/src/InputWasm.tsx
  38. 3 1
      packages/react-components/src/Label.tsx
  39. 3 1
      packages/react-components/src/Labelled.tsx
  40. 3 1
      packages/react-components/src/LockedVote.tsx
  41. 11 2
      packages/react-components/src/Modal.tsx
  42. 3 1
      packages/react-components/src/Nonce.tsx
  43. 3 1
      packages/react-components/src/Output.tsx
  44. 3 1
      packages/react-components/src/Params/Call.tsx
  45. 3 1
      packages/react-components/src/Params/Extrinsic.tsx
  46. 3 1
      packages/react-components/src/Params/Proposal.tsx
  47. 3 1
      packages/react-components/src/Password.tsx
  48. 3 1
      packages/react-components/src/Progress.tsx
  49. 3 1
      packages/react-components/src/Static.tsx
  50. 3 1
      packages/react-components/src/Status/Queue.tsx
  51. 5 6
      packages/react-components/src/Table.tsx
  52. 3 1
      packages/react-components/src/Tabs.tsx
  53. 3 1
      packages/react-components/src/TreasuryProposal.tsx
  54. 3 1
      packages/react-components/src/TxButton.tsx
  55. 3 1
      packages/react-components/src/VoteAccount.tsx
  56. 3 1
      packages/react-components/src/VoteActions.tsx
  57. 3 1
      packages/react-components/src/VoteToggle.tsx
  58. 12 3
      packages/react-components/src/styles/index.ts
  59. 1 1
      packages/react-components/src/styles/theme.ts

+ 3 - 1
packages/react-api/src/Api.tsx

@@ -118,7 +118,7 @@ async function loadOnReady (api: ApiPromise): Promise<State> {
   } as State;
 }
 
-export default function Api ({ children, url }: Props): React.ReactElement<Props> | null {
+function Api ({ children, url }: Props): React.ReactElement<Props> | null {
   const { queuePayload, queueSetTxStatus } = useContext(StatusContext);
   const [state, setState] = useState<State>({ isApiReady: false } as Partial<State> as State);
   const [isApiConnected, setIsApiConnected] = useState(false);
@@ -159,3 +159,5 @@ export default function Api ({ children, url }: Props): React.ReactElement<Props
     </ApiContext.Provider>
   );
 }
+
+export default React.memo(Api);

+ 3 - 1
packages/react-components/src/AccountNameJudgement.tsx

@@ -30,7 +30,7 @@ const JUDGEMENT_ENUM = [
   { value: 5, text: 'Low quality' }
 ];
 
-export default function AccountNameJudgement ({ address, toggleJudgement }: Props): React.ReactElement<Props> {
+function AccountNameJudgement ({ address, toggleJudgement }: Props): React.ReactElement<Props> {
   const { t } = useTranslation();
   const { api } = useApi();
   const registrars = useCall<Option<RegistrarInfo>[]>(api.query.identity?.registrars, []);
@@ -91,3 +91,5 @@ export default function AccountNameJudgement ({ address, toggleJudgement }: Prop
     </Modal>
   );
 }
+
+export default React.memo(AccountNameJudgement);

+ 3 - 1
packages/react-components/src/Available.tsx

@@ -15,7 +15,7 @@ export interface Props extends BareProps {
   params?: AccountId | AccountIndex | Address | string | Uint8Array | null;
 }
 
-export default function AvailableDisplay ({ params, className, label, style }: Props): React.ReactElement<Props> | null {
+function AvailableDisplay ({ params, className, label, style }: Props): React.ReactElement<Props> | null {
   if (!params) {
     return null;
   }
@@ -29,3 +29,5 @@ export default function AvailableDisplay ({ params, className, label, style }: P
     />
   );
 }
+
+export default React.memo(AvailableDisplay);

+ 3 - 1
packages/react-components/src/Balance.tsx

@@ -51,7 +51,7 @@ export function renderProvided ({ className, label, value }: RenderProps): React
   );
 }
 
-export default function BalanceDisplay (props: Props): React.ReactElement<Props> | null {
+function BalanceDisplay (props: Props): React.ReactElement<Props> | null {
   const { balance, className, label, params, style } = props;
 
   if (!params) {
@@ -73,3 +73,5 @@ export default function BalanceDisplay (props: Props): React.ReactElement<Props>
       />
     );
 }
+
+export default React.memo(BalanceDisplay);

+ 3 - 1
packages/react-components/src/Bonded.tsx

@@ -19,7 +19,7 @@ export interface Props extends BareProps {
   withLabel?: boolean;
 }
 
-export default function BondedDisplay (props: Props): React.ReactElement<Props> | null {
+function BondedDisplay (props: Props): React.ReactElement<Props> | null {
   const { bonded, params, className, label, style } = props;
 
   if (!params) {
@@ -41,3 +41,5 @@ export default function BondedDisplay (props: Props): React.ReactElement<Props>
       />
     );
 }
+
+export default React.memo(BondedDisplay);

+ 3 - 1
packages/react-components/src/Button/Button.tsx

@@ -13,7 +13,7 @@ import Tooltip from '../Tooltip';
 
 let idCounter = 0;
 
-export default function Button ({ children, className, floated, icon, isBasic = false, isCircular = false, isDisabled = false, isFluid = false, isLoading = false, isNegative = false, isPositive = false, isPrimary = false, label, labelPosition, onClick, size, style, tabIndex, tooltip }: ButtonProps): React.ReactElement<ButtonProps> {
+function Button ({ children, className, floated, icon, isBasic = false, isCircular = false, isDisabled = false, isFluid = false, isLoading = false, isNegative = false, isPositive = false, isPrimary = false, label, labelPosition, onClick, size, style, tabIndex, tooltip }: ButtonProps): React.ReactElement<ButtonProps> {
   const [triggerId] = useState(`button-${++idCounter}`);
   const props = {
     basic: isBasic,
@@ -60,3 +60,5 @@ export default function Button ({ children, className, floated, icon, isBasic =
     </>
   );
 }
+
+export default React.memo(Button);

+ 3 - 1
packages/react-components/src/Button/Divider.tsx

@@ -8,7 +8,7 @@ import React from 'react';
 
 import { classes } from '../util';
 
-export default function ButtonDivider ({ className, style }: DividerProps): React.ReactElement<DividerProps> {
+function ButtonDivider ({ className, style }: DividerProps): React.ReactElement<DividerProps> {
   return (
     <div
       className={classes('ui button compact mini basic', className)}
@@ -16,3 +16,5 @@ export default function ButtonDivider ({ className, style }: DividerProps): Reac
     />
   );
 }
+
+export default React.memo(ButtonDivider);

+ 3 - 1
packages/react-components/src/Button/Or.tsx

@@ -14,7 +14,7 @@ interface Props {
   text?: string;
 }
 
-export default function ButtonOr ({ className, style, text }: Props): React.ReactElement<Props> {
+function ButtonOr ({ className, style, text }: Props): React.ReactElement<Props> {
   const { t } = useTranslation();
 
   return (
@@ -29,3 +29,5 @@ export default function ButtonOr ({ className, style, text }: Props): React.Reac
     />
   );
 }
+
+export default React.memo(ButtonOr);

+ 3 - 2
packages/react-components/src/ButtonCancel.tsx

@@ -14,8 +14,7 @@ interface Props {
   onClick: () => void;
   tabIndex?: number;
 }
-
-export default function ButtonCancel ({ className, isDisabled, label, onClick, tabIndex }: Props): React.ReactElement<Props> {
+function ButtonCancel ({ className, isDisabled, label, onClick, tabIndex }: Props): React.ReactElement<Props> {
   const { t } = useTranslation();
 
   return (
@@ -30,3 +29,5 @@ export default function ButtonCancel ({ className, isDisabled, label, onClick, t
     />
   );
 }
+
+export default React.memo(ButtonCancel);

+ 4 - 6
packages/react-components/src/Chart/Base.tsx

@@ -2,17 +2,13 @@
 // This software may be modified and distributed under the terms
 // of the Apache-2.0 license. See the LICENSE file for details.
 
-import { BareProps } from '../types';
+import { BaseProps } from './types';
 
 import React from 'react';
 import styled from 'styled-components';
 
 import { classes } from '../util';
 
-interface Props extends BareProps {
-  children: React.ReactNode;
-}
-
 const Wrapper = styled.div`
   position: relative;
   display: inline-block;
@@ -21,7 +17,7 @@ const Wrapper = styled.div`
   width: 15vw;
 `;
 
-export default function BaseChart ({ children, className, style }: Props): React.ReactElement<Props> {
+function BaseChart ({ children, className, style }: BaseProps): React.ReactElement<BaseProps> {
   return (
     <Wrapper
       className={classes('ui--Chart', className)}
@@ -31,3 +27,5 @@ export default function BaseChart ({ children, className, style }: Props): React
     </Wrapper>
   );
 }
+
+export default React.memo(BaseChart);

+ 4 - 14
packages/react-components/src/Chart/Doughnut.tsx

@@ -2,26 +2,14 @@
 // This software may be modified and distributed under the terms
 // of the Apache-2.0 license. See the LICENSE file for details.
 
-import { BareProps } from '../types';
+import { DoughnutProps } from './types';
 
-import BN from 'bn.js';
 import React from 'react';
 import { Doughnut } from 'react-chartjs-2';
 import { bnToBn } from '@polkadot/util';
 
 import Base from './Base';
 
-interface Value {
-  colors: string[];
-  label: string;
-  value: number | BN;
-}
-
-interface Props extends BareProps {
-  size?: number;
-  values: Value[];
-}
-
 interface Options {
   colorNormal: string[];
   colorHover: string[];
@@ -29,7 +17,7 @@ interface Options {
   labels: string[];
 }
 
-export default function ChartDoughnut ({ className, size = 100, style, values }: Props): React.ReactElement<Props> {
+function ChartDoughnut ({ className, size = 100, style, values }: DoughnutProps): React.ReactElement<DoughnutProps> {
   const options: Options = {
     colorNormal: [],
     colorHover: [],
@@ -69,3 +57,5 @@ export default function ChartDoughnut ({ className, size = 100, style, values }:
     </Base>
   );
 }
+
+export default React.memo(ChartDoughnut);

+ 5 - 19
packages/react-components/src/Chart/HorizBar.tsx

@@ -3,29 +3,13 @@
 // This software may be modified and distributed under the terms
 // of the Apache-2.0 license. See the LICENSE file for details.
 
-import { BareProps } from '../types';
+import { HorizBarProps, HorizBarValue } from './types';
 
-import BN from 'bn.js';
 import React, { useEffect, useState } from 'react';
 import ChartJs from 'chart.js';
 import { HorizontalBar } from 'react-chartjs-2';
 import { bnToBn, isNumber } from '@polkadot/util';
 
-interface Value {
-  colors: string[];
-  label: string;
-  tooltip?: string;
-  value: number | BN;
-}
-
-interface Props extends BareProps {
-  aspectRatio?: number;
-  max?: number;
-  showLabels?: boolean;
-  values: Value[];
-  withColors?: boolean;
-}
-
 interface State {
   chartData?: ChartJs.ChartData;
   chartOptions?: ChartJs.ChartOptions;
@@ -48,7 +32,7 @@ interface Config {
 const alphaColor = (hexColor: string): string =>
   ChartJs.helpers.color(hexColor).alpha(0.65).rgbString();
 
-function calculateOptions (aspectRatio: number, values: Value[], jsonValues: string, max: number, showLabels: boolean): State {
+function calculateOptions (aspectRatio: number, values: HorizBarValue[], jsonValues: string, max: number, showLabels: boolean): State {
   const chartData = values.reduce((data, { colors: [normalColor = '#00f', hoverColor], label, value }): Config => {
     const dataset = data.datasets[0];
 
@@ -94,7 +78,7 @@ function calculateOptions (aspectRatio: number, values: Value[], jsonValues: str
   };
 }
 
-export default function ChartHorizBar ({ aspectRatio = 8, className, max = 100, showLabels = false, style, values }: Props): React.ReactElement<Props> | null {
+function ChartHorizBar ({ aspectRatio = 8, className, max = 100, showLabels = false, style, values }: HorizBarProps): React.ReactElement<HorizBarProps> | null {
   const [{ chartData, chartOptions, jsonValues }, setState] = useState<State>({});
 
   useEffect((): void => {
@@ -124,3 +108,5 @@ export default function ChartHorizBar ({ aspectRatio = 8, className, max = 100,
     </div>
   );
 }
+
+export default React.memo(ChartHorizBar);

+ 4 - 9
packages/react-components/src/Chart/Line.tsx

@@ -2,20 +2,13 @@
 // This software may be modified and distributed under the terms
 // of the Apache-2.0 license. See the LICENSE file for details.
 
-import { BareProps } from '../types';
+import { LineProps } from './types';
 
 import BN from 'bn.js';
 import React, { useEffect, useState } from 'react';
 import ChartJs from 'chart.js';
 import { Line } from 'react-chartjs-2';
 
-interface Props extends BareProps {
-  colors?: (string | undefined)[];
-  labels: string[];
-  legends: string[];
-  values: (number | BN)[][];
-}
-
 interface State {
   chartData?: ChartJs.ChartData;
   chartOptions?: ChartJs.ChartOptions;
@@ -80,7 +73,7 @@ function calculateOptions (colors: (string | undefined)[] = [], legends: string[
   };
 }
 
-export default function LineChart ({ className, colors, labels, legends, style, values }: Props): React.ReactElement<Props> | null {
+function LineChart ({ className, colors, labels, legends, style, values }: LineProps): React.ReactElement<LineProps> | null {
   const [{ chartData, chartOptions, jsonValues }, setState] = useState<State>({});
 
   useEffect((): void => {
@@ -107,3 +100,5 @@ export default function LineChart ({ className, colors, labels, legends, style,
     </div>
   );
 }
+
+export default React.memo(LineChart);

+ 3 - 1
packages/react-components/src/Chart/index.ts

@@ -6,8 +6,10 @@ import Doughnut from './Doughnut';
 import HorizBar from './HorizBar';
 import Line from './Line';
 
-export default {
+const Chart = {
   Doughnut,
   HorizBar,
   Line
 };
+
+export default Chart;

+ 44 - 0
packages/react-components/src/Chart/types.ts

@@ -0,0 +1,44 @@
+// Copyright 2017-2020 @polkadot/react-components authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { BareProps } from '../types';
+
+import BN from 'bn.js';
+
+export interface DoughnutValue {
+  colors: string[];
+  label: string;
+  value: number | BN;
+}
+
+export interface HorizBarValue {
+  colors: string[];
+  label: string;
+  tooltip?: string;
+  value: number | BN;
+}
+
+export interface BaseProps extends BareProps {
+  children: React.ReactNode;
+}
+
+export interface DoughnutProps extends BareProps {
+  size?: number;
+  values: DoughnutValue[];
+}
+
+export interface HorizBarProps extends BareProps {
+  aspectRatio?: number;
+  max?: number;
+  showLabels?: boolean;
+  values: HorizBarValue[];
+  withColors?: boolean;
+}
+
+export interface LineProps extends BareProps {
+  colors?: (string | undefined)[];
+  labels: string[];
+  legends: string[];
+  values: (number | BN)[][];
+}

+ 3 - 1
packages/react-components/src/CryptoType.tsx

@@ -15,7 +15,7 @@ interface Props extends BareProps {
   label?: string;
 }
 
-export default function CryptoType ({ accountId, className, label = '' }: Props): React.ReactElement<Props> {
+function CryptoType ({ accountId, className, label = '' }: Props): React.ReactElement<Props> {
   const [type, setType] = useState('unknown');
 
   useEffect((): void => {
@@ -46,3 +46,5 @@ export default function CryptoType ({ accountId, className, label = '' }: Props)
     </div>
   );
 }
+
+export default React.memo(CryptoType);

+ 23 - 18
packages/react-components/src/Dropdown.tsx

@@ -4,7 +4,7 @@
 
 import { BareProps } from './types';
 
-import React, { useEffect, useRef, useState } from 'react';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
 import styled from 'styled-components';
 import SUIButton from 'semantic-ui-react/dist/commonjs/elements/Button/Button';
 import SUIDropdown, { DropdownProps } from 'semantic-ui-react/dist/commonjs/modules/Dropdown/Dropdown';
@@ -44,24 +44,27 @@ export type IDropdown<Option> = React.ComponentType<Props<Option>> & {
   Header: React.ComponentType<{ content: React.ReactNode }>;
 }
 
-function Dropdown<Option> ({ allowAdd = false, className, defaultValue, dropdownClassName, help, isButton, isDisabled, isError, isFull, isMultiple, label, labelExtra, onAdd, onBlur, onChange, onClose, onSearch, options, placeholder, renderLabel, searchInput, style, transform, withEllipsis, withLabel, value }: Props<Option>): React.ReactElement<Props<Option>> {
+function BaseDropdown<Option> ({ allowAdd = false, className, defaultValue, dropdownClassName, help, isButton, isDisabled, isError, isFull, isMultiple, label, labelExtra, onAdd, onBlur, onChange, onClose, onSearch, options, placeholder, renderLabel, searchInput, style, transform, withEllipsis, withLabel, value }: Props<Option>): React.ReactElement<Props<Option>> {
   const lastUpdate = useRef<string>('');
   const [stored, setStored] = useState<any>();
 
-  const _setStored = (value: any): void => {
-    const json = JSON.stringify({ v: value });
+  const _setStored = useCallback(
+    (value: any): void => {
+      const json = JSON.stringify({ v: value });
 
-    if (lastUpdate.current !== json) {
-      lastUpdate.current = json;
+      if (lastUpdate.current !== json) {
+        lastUpdate.current = json;
 
-      setStored(value);
-      onChange && onChange(
-        transform
-          ? transform(value)
-          : value
-      );
-    }
-  };
+        setStored(value);
+        onChange && onChange(
+          transform
+            ? transform(value)
+            : value
+        );
+      }
+    },
+    []
+  );
 
   useEffect((): void => {
     _setStored(isUndefined(value) ? defaultValue : value);
@@ -119,9 +122,7 @@ function Dropdown<Option> ({ allowAdd = false, className, defaultValue, dropdown
     );
 }
 
-Dropdown.Header = SUIDropdown.Header;
-
-export default styled(Dropdown)`
+const Dropdown = React.memo(styled(BaseDropdown)`
   .ui--Dropdown-item {
     position: relative;
     white-space: nowrap;
@@ -157,4 +158,8 @@ export default styled(Dropdown)`
       }
     }
   }
-`;
+`) as unknown as IDropdown<any>;
+
+(Dropdown as any).Header = SUIDropdown.Header;
+
+export default Dropdown;

+ 3 - 1
packages/react-components/src/Event.tsx

@@ -17,7 +17,7 @@ export interface Props extends BareProps {
   value: Event;
 }
 
-export default function EventDisplay ({ children, className, style, value }: Props): React.ReactElement<Props> {
+function EventDisplay ({ children, className, style, value }: Props): React.ReactElement<Props> {
   const params = value.typeDef.map(({ type }): { type: TypeDef } => ({
     type: getTypeDef(type)
   }));
@@ -40,3 +40,5 @@ export default function EventDisplay ({ children, className, style, value }: Pro
     </div>
   );
 }
+
+export default React.memo(EventDisplay);

+ 12 - 7
packages/react-components/src/Expander.tsx

@@ -4,22 +4,25 @@
 
 import { BareProps } from './types';
 
-import React, { useState } from 'react';
+import React, { useCallback, useState } from 'react';
 
 export interface Props extends BareProps {
   children: React.ReactNode;
   summary: React.ReactNode;
 }
 
-export default function Expanded ({ children, className, summary }: Props): React.ReactElement<Props> {
+function Expander ({ children, className, summary }: Props): React.ReactElement<Props> {
   const [isExpanded, setIsExpanded] = useState(false);
 
-  const _toggle = (event: React.SyntheticEvent): void => {
-    event.preventDefault();
-    event.stopPropagation();
+  const _toggle = useCallback(
+    (event: React.SyntheticEvent): void => {
+      event.preventDefault();
+      event.stopPropagation();
 
-    setIsExpanded(!isExpanded);
-  };
+      setIsExpanded((isExpanded) => !isExpanded);
+    },
+    []
+  );
 
   return (
     <details
@@ -31,3 +34,5 @@ export default function Expanded ({ children, className, summary }: Props): Reac
     </details>
   );
 }
+
+export default React.memo(Expander);

+ 3 - 1
packages/react-components/src/Extrinsic.tsx

@@ -34,7 +34,7 @@ function getParams ({ meta }: SubmittableExtrinsicFunction<'promise'>): { name:
   }));
 }
 
-export default function ExtrinsicDisplay ({ defaultValue, isDisabled, isError, isPrivate, label, onChange, onEnter, onEscape, withLabel }: Props): React.ReactElement<Props> {
+function ExtrinsicDisplay ({ defaultValue, isDisabled, isError, isPrivate, label, onChange, onEnter, onEscape, withLabel }: Props): React.ReactElement<Props> {
   const [extrinsic, setCall] = useState<{ fn: SubmittableExtrinsicFunction<'promise'>; params: { name: string; type: TypeDef }[] }>({ fn: defaultValue, params: getParams(defaultValue) });
   const [values, setValues] = useState<RawParam[]>([]);
 
@@ -90,3 +90,5 @@ export default function ExtrinsicDisplay ({ defaultValue, isDisabled, isError, i
     </div>
   );
 }
+
+export default React.memo(ExtrinsicDisplay);

+ 3 - 1
packages/react-components/src/Input.tsx

@@ -90,7 +90,7 @@ const isSelectAll = (key: string, isPreKeyDown: boolean): boolean =>
 
 let counter = 0;
 
-export default function Input ({ autoFocus = false, children, className, defaultValue, help, icon, inputClassName, isEditable = false, isAction = false, isDisabled = false, isDisabledError = false, isError = false, isFull = false, isHidden = false, isReadOnly = false, label, labelExtra, max, maxLength, min, name, onBlur, onChange, onEnter, onEscape, onKeyDown, onKeyUp, onPaste, placeholder, style, tabIndex, type = 'text', value, withEllipsis, withLabel }: Props): React.ReactElement<Props> {
+function Input ({ autoFocus = false, children, className, defaultValue, help, icon, inputClassName, isEditable = false, isAction = false, isDisabled = false, isDisabledError = false, isError = false, isFull = false, isHidden = false, isReadOnly = false, label, labelExtra, max, maxLength, min, name, onBlur, onChange, onEnter, onEscape, onKeyDown, onKeyUp, onPaste, placeholder, style, tabIndex, type = 'text', value, withEllipsis, withLabel }: Props): React.ReactElement<Props> {
   const [stateName] = useState(`in_${counter++}_at_${Date.now()}`);
 
   const _onBlur = (): void => {
@@ -190,6 +190,8 @@ export default function Input ({ autoFocus = false, children, className, default
   );
 }
 
+export default React.memo(Input);
+
 export {
   isCopy,
   isCut,

+ 3 - 1
packages/react-components/src/InputConsts/SelectKey.tsx

@@ -29,7 +29,7 @@ function transform ({ value }: Props): (method: string) => ConstValueBase {
   };
 }
 
-export default function SelectKey (props: Props): React.ReactElement<Props> | null {
+function SelectKey (props: Props): React.ReactElement<Props> | null {
   const { className, isError, onChange, options, style, value } = props;
 
   if (!options.length) {
@@ -49,3 +49,5 @@ export default function SelectKey (props: Props): React.ReactElement<Props> | nu
     />
   );
 }
+
+export default React.memo(SelectKey);

+ 3 - 1
packages/react-components/src/InputConsts/SelectSection.tsx

@@ -19,7 +19,7 @@ interface Props extends BareProps {
   value: ConstValueBase;
 }
 
-export default function SelectSection ({ className, defaultValue, isError, onChange, options, style, value: { section } }: Props): React.ReactElement<Props> {
+function SelectSection ({ className, defaultValue, isError, onChange, options, style, value: { section } }: Props): React.ReactElement<Props> {
   return (
     <Dropdown
       className={classes('ui--DropdownLinked-Sections', className)}
@@ -33,3 +33,5 @@ export default function SelectSection ({ className, defaultValue, isError, onCha
     />
   );
 }
+
+export default React.memo(SelectSection);

+ 3 - 1
packages/react-components/src/InputConsts/index.tsx

@@ -40,7 +40,7 @@ function getValue (api: ApiPromise, { method, section }: ConstValueBase): ConstV
   };
 }
 
-export default function InputConsts ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
+function InputConsts ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
   const { api } = useApi();
   const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(keyOptions(api, defaultValue.section));
   const [optionsSection] = useState<DropdownOptions>(sectionOptions(api));
@@ -92,3 +92,5 @@ export default function InputConsts ({ className, defaultValue, help, label, onC
     </LinkedWrapper>
   );
 }
+
+export default React.memo(InputConsts);

+ 3 - 1
packages/react-components/src/InputError.tsx

@@ -17,7 +17,7 @@ const defaultLabel: React.ReactNode = (
   <div>&nbsp;</div>
 );
 
-export default function InputError ({ className, label = defaultLabel, style }: Props): React.ReactElement<Props> {
+function InputError ({ className, label = defaultLabel, style }: Props): React.ReactElement<Props> {
   return (
     <div
       className={classes('ui--InputError', className)}
@@ -27,3 +27,5 @@ export default function InputError ({ className, label = defaultLabel, style }:
     </div>
   );
 }
+
+export default React.memo(InputError);

+ 3 - 1
packages/react-components/src/InputExtrinsic/SelectMethod.tsx

@@ -20,7 +20,7 @@ interface Props extends BareProps {
   value: SubmittableExtrinsicFunction<'promise'>;
 }
 
-export default function SelectMethod ({ api, className, isError, onChange, options, style, value }: Props): React.ReactElement<Props> | null {
+function SelectMethod ({ api, className, isError, onChange, options, style, value }: Props): React.ReactElement<Props> | null {
   if (!options.length) {
     return null;
   }
@@ -40,3 +40,5 @@ export default function SelectMethod ({ api, className, isError, onChange, optio
     />
   );
 }
+
+export default React.memo(SelectMethod);

+ 3 - 1
packages/react-components/src/InputExtrinsic/SelectSection.tsx

@@ -19,7 +19,7 @@ interface Props extends BareProps {
   value: SubmittableExtrinsicFunction<'promise'>;
 }
 
-export default function SelectSection ({ className, defaultValue, isError, onChange, options, style, value }: Props): React.ReactElement<Props> {
+function SelectSection ({ className, defaultValue, isError, onChange, options, style, value }: Props): React.ReactElement<Props> {
   return (
     <Dropdown
       className={classes('ui--DropdownLinked-Sections', className)}
@@ -33,3 +33,5 @@ export default function SelectSection ({ className, defaultValue, isError, onCha
     />
   );
 }
+
+export default React.memo(SelectSection);

+ 3 - 1
packages/react-components/src/InputExtrinsic/index.tsx

@@ -27,7 +27,7 @@ interface Props {
   withLabel?: boolean;
 }
 
-export default function InputExtrinsic ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
+function InputExtrinsic ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
   const { api } = useApi();
   const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(methodOptions(api, defaultValue.section));
   const [optionsSection] = useState<DropdownOptions>(sectionOptions(api));
@@ -77,3 +77,5 @@ export default function InputExtrinsic ({ className, defaultValue, help, label,
     </LinkedWrapper>
   );
 }
+
+export default React.memo(InputExtrinsic);

+ 3 - 1
packages/react-components/src/InputNumber.tsx

@@ -193,7 +193,7 @@ function isNewPropsValue (propsValue: BN | string, value: string, valueBn: BN):
   return BN.isBN(propsValue) ? !propsValue.eq(valueBn) : propsValue !== value;
 }
 
-export default function InputNumber (props: Props): React.ReactElement<Props> {
+function InputNumber (props: Props): React.ReactElement<Props> {
   const { t } = useTranslation();
   const { bitLength = DEFAULT_BITLENGTH, className, defaultValue = ZERO, help, isDecimal, isFull, isSi, isDisabled, isError = false, maxLength, maxValue, onChange, onEnter, onEscape, placeholder, style, value: propsValue } = props;
 
@@ -302,3 +302,5 @@ export default function InputNumber (props: Props): React.ReactElement<Props> {
     </Input>
   );
 }
+
+export default React.memo(InputNumber);

+ 3 - 1
packages/react-components/src/InputRpc/SelectMethod.tsx

@@ -26,7 +26,7 @@ function transform ({ value }: Props): (method: string) => RpcMethod {
   };
 }
 
-export default function SelectMethod (props: Props): React.ReactElement<Props> | null {
+function SelectMethod (props: Props): React.ReactElement<Props> | null {
   const { className, isError, onChange, options, style, value } = props;
 
   if (!options.length) {
@@ -46,3 +46,5 @@ export default function SelectMethod (props: Props): React.ReactElement<Props> |
     />
   );
 }
+
+export default React.memo(SelectMethod);

+ 3 - 1
packages/react-components/src/InputRpc/SelectSection.tsx

@@ -19,7 +19,7 @@ interface Props extends BareProps {
   value: RpcMethod;
 }
 
-export default function SelectSection ({ className, defaultValue, isError, onChange, options, style, value }: Props): React.ReactElement<Props> {
+function SelectSection ({ className, defaultValue, isError, onChange, options, style, value }: Props): React.ReactElement<Props> {
   return (
     <Dropdown
       className={classes('ui--DropdownLinked-Sections', className)}
@@ -33,3 +33,5 @@ export default function SelectSection ({ className, defaultValue, isError, onCha
     />
   );
 }
+
+export default React.memo(SelectSection);

+ 3 - 1
packages/react-components/src/InputRpc/index.tsx

@@ -28,7 +28,7 @@ interface Props {
   withLabel?: boolean;
 }
 
-export default function InputRpc ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
+function InputRpc ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
   const { api } = useApi();
   const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(methodOptions(api, defaultValue.section));
   const [optionsSection] = useState<DropdownOptions>(sectionOptions(api));
@@ -77,3 +77,5 @@ export default function InputRpc ({ className, defaultValue, help, label, onChan
     </LinkedWrapper>
   );
 }
+
+export default React.memo(InputRpc);

+ 3 - 1
packages/react-components/src/InputStorage/SelectKey.tsx

@@ -28,7 +28,7 @@ function transform (api: ApiPromise, { value }: Props): (method: string) => Stor
   };
 }
 
-export default function SelectKey (props: Props): React.ReactElement<Props> | null {
+function SelectKey (props: Props): React.ReactElement<Props> | null {
   const { api } = useApi();
   const { className, isError, onChange, options, style, value } = props;
 
@@ -49,3 +49,5 @@ export default function SelectKey (props: Props): React.ReactElement<Props> | nu
     />
   );
 }
+
+export default React.memo(SelectKey);

+ 3 - 1
packages/react-components/src/InputStorage/SelectSection.tsx

@@ -19,7 +19,7 @@ interface Props extends BareProps {
   value: StorageEntryPromise;
 }
 
-export default function SelectSection ({ className, defaultValue, isError, onChange, options, style, value: { creator: { section } } }: Props): React.ReactElement<Props> {
+function SelectSection ({ className, defaultValue, isError, onChange, options, style, value: { creator: { section } } }: Props): React.ReactElement<Props> {
   return (
     <Dropdown
       className={classes('ui--DropdownLinked-Sections', className)}
@@ -33,3 +33,5 @@ export default function SelectSection ({ className, defaultValue, isError, onCha
     />
   );
 }
+
+export default React.memo(SelectSection);

+ 3 - 1
packages/react-components/src/InputStorage/index.tsx

@@ -27,7 +27,7 @@ interface Props {
   withLabel?: boolean;
 }
 
-export default function InputStorage ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
+function InputStorage ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
   const { api } = useApi();
   const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(keyOptions(api, defaultValue.creator.section));
   const [optionsSection] = useState<DropdownOptions>(sectionOptions(api));
@@ -76,3 +76,5 @@ export default function InputStorage ({ className, defaultValue, help, label, on
     </LinkedWrapper>
   );
 }
+
+export default React.memo(InputStorage);

+ 3 - 1
packages/react-components/src/InputTags.tsx

@@ -55,7 +55,7 @@ function onAddTag (value: string): void {
   saveTags(tags);
 }
 
-export default function InputTags ({ allowAdd = true, className, defaultValue, help, isDisabled, isError, label, onBlur, onChange, onClose, placeholder, searchInput, value, withLabel }: Props): React.ReactElement<Props> {
+function InputTags ({ allowAdd = true, className, defaultValue, help, isDisabled, isError, label, onBlur, onChange, onClose, placeholder, searchInput, value, withLabel }: Props): React.ReactElement<Props> {
   return (
     <Dropdown
       allowAdd={allowAdd && !isDisabled}
@@ -78,3 +78,5 @@ export default function InputTags ({ allowAdd = true, className, defaultValue, h
     />
   );
 }
+
+export default React.memo(InputTags);

+ 3 - 1
packages/react-components/src/InputWasm.tsx

@@ -11,7 +11,7 @@ interface Props extends Omit<InputFileProps, 'accept'> {
   onChange: (contents: Uint8Array, name?: string) => void;
 }
 
-export default function InputWasm ({ isValidRef, onChange, ...props }: Props): React.ReactElement<Props> {
+function InputWasm ({ isValidRef, onChange, ...props }: Props): React.ReactElement<Props> {
   const _onChange = (wasm: Uint8Array, name: string): void => {
     const isWasmValid = wasm.subarray(0, 4).toString() === '0,97,115,109'; // '\0asm'
 
@@ -27,3 +27,5 @@ export default function InputWasm ({ isValidRef, onChange, ...props }: Props): R
     />
   );
 }
+
+export default React.memo(InputWasm);

+ 3 - 1
packages/react-components/src/Label.tsx

@@ -14,7 +14,7 @@ interface Props extends BareProps {
   withEllipsis?: boolean;
 }
 
-export default function Label ({ className, help, label, withEllipsis }: Props): React.ReactElement<Props> {
+function Label ({ className, help, label, withEllipsis }: Props): React.ReactElement<Props> {
   return (
     <label className={className}>
       {
@@ -25,3 +25,5 @@ export default function Label ({ className, help, label, withEllipsis }: Props):
     </label>
   );
 }
+
+export default React.memo(Label);

+ 3 - 1
packages/react-components/src/Labelled.tsx

@@ -132,7 +132,7 @@ const Wrapper = styled.div`
   }
 `;
 
-export default function Labelled ({ className, children, help, isFull, isHidden, isOuter, isSmall, label = defaultLabel, labelExtra, style, withEllipsis, withLabel = true }: Props): React.ReactElement<Props> | null {
+function Labelled ({ className, children, help, isFull, isHidden, isOuter, isSmall, label = defaultLabel, labelExtra, style, withEllipsis, withLabel = true }: Props): React.ReactElement<Props> | null {
   if (isHidden) {
     return null;
   } else if (!withLabel) {
@@ -160,3 +160,5 @@ export default function Labelled ({ className, children, help, isFull, isHidden,
     </Wrapper>
   );
 }
+
+export default React.memo(Labelled);

+ 3 - 1
packages/react-components/src/LockedVote.tsx

@@ -16,7 +16,7 @@ export interface Props extends BareProps {
   withLabel?: boolean;
 }
 
-export default function LockedVoteDisplay (props: Props): React.ReactElement<Props> | null {
+function LockedVoteDisplay (props: Props): React.ReactElement<Props> | null {
   const { params, className, label, style } = props;
 
   if (!params) {
@@ -32,3 +32,5 @@ export default function LockedVoteDisplay (props: Props): React.ReactElement<Pro
     />
   );
 }
+
+export default React.memo(LockedVoteDisplay);

+ 11 - 2
packages/react-components/src/Modal.tsx

@@ -25,7 +25,14 @@ interface ActionsProps extends BareProps {
   onCancel: () => void;
 }
 
-function Modal (props: ModalProps): React.ReactElement<ModalProps> {
+type ModalType = React.FC<ModalProps> & {
+  Actions: React.FC<ActionsProps>;
+  Content: typeof SUIModal.Content;
+  Header: typeof SUIModal.Header;
+  Description: typeof SUIModal.Description;
+};
+
+function ModalBase (props: ModalProps): React.ReactElement<ModalProps> {
   const { className, children, header, open = true } = props;
 
   return (
@@ -56,7 +63,9 @@ function Actions ({ cancelLabel, className, children, withOr = true, onCancel }:
   );
 }
 
-Modal.Actions = Actions;
+const Modal = React.memo(ModalBase) as unknown as ModalType;
+
+Modal.Actions = React.memo(Actions);
 Modal.Content = SUIModal.Content;
 Modal.Header = SUIModal.Header;
 Modal.Description = SUIModal.Description;

+ 3 - 1
packages/react-components/src/Nonce.tsx

@@ -15,7 +15,7 @@ export interface Props extends BareProps {
   params?: AccountId | AccountIndex | Address | string | Uint8Array | null;
 }
 
-export default function NonceDisplay ({ className, label, params, style }: Props): React.ReactElement<Props> | null {
+function NonceDisplay ({ className, label, params, style }: Props): React.ReactElement<Props> | null {
   if (!params) {
     return null;
   }
@@ -29,3 +29,5 @@ export default function NonceDisplay ({ className, label, params, style }: Props
     />
   );
 }
+
+export default React.memo(NonceDisplay);

+ 3 - 1
packages/react-components/src/Output.tsx

@@ -22,7 +22,7 @@ interface Props extends BareProps {
   withLabel?: boolean;
 }
 
-export default function Output ({ className, children, help, isError, isHidden, isMonospace, label, style, value, withCopy = false, withLabel }: Props): React.ReactElement<Props> {
+function Output ({ className, children, help, isError, isHidden, isMonospace, label, style, value, withCopy = false, withLabel }: Props): React.ReactElement<Props> {
   return (
     <Labelled
       className={className}
@@ -49,3 +49,5 @@ export default function Output ({ className, children, help, isError, isHidden,
     </Labelled>
   );
 }
+
+export default React.memo(Output);

+ 3 - 1
packages/react-components/src/Params/Call.tsx

@@ -10,7 +10,7 @@ import { useApi } from '@polkadot/react-hooks';
 
 import Extrinsic from './Extrinsic';
 
-export default function Call ({ className, isDisabled, isError, label, onChange, onEnter, onEscape, style, withLabel }: Props): React.ReactElement<Props> {
+function Call ({ className, isDisabled, isError, label, onChange, onEnter, onEscape, style, withLabel }: Props): React.ReactElement<Props> {
   const { api, apiDefaultTx } = useApi();
 
   const defaultValue = ((): SubmittableExtrinsicFunction<'promise'> => {
@@ -37,3 +37,5 @@ export default function Call ({ className, isDisabled, isError, label, onChange,
     />
   );
 }
+
+export default React.memo(Call);

+ 3 - 1
packages/react-components/src/Params/Extrinsic.tsx

@@ -31,7 +31,7 @@ function onChange ({ onChange }: Props): (method?: SubmittableExtrinsic<'promise
   };
 }
 
-export default function ExtrinsicDisplay (props: Props): React.ReactElement<Props> {
+function ExtrinsicDisplay (props: Props): React.ReactElement<Props> {
   const { className, defaultValue, isDisabled, isError, isPrivate, label, onEnter, onEscape, style, withLabel } = props;
 
   return (
@@ -50,3 +50,5 @@ export default function ExtrinsicDisplay (props: Props): React.ReactElement<Prop
     />
   );
 }
+
+export default React.memo(ExtrinsicDisplay);

+ 3 - 1
packages/react-components/src/Params/Proposal.tsx

@@ -26,7 +26,7 @@ function onChange ({ onChange }: Props): (_: RawParam) => void {
   };
 }
 
-export default function ProposalDisplay (props: Props): React.ReactElement<Props> {
+function ProposalDisplay (props: Props): React.ReactElement<Props> {
   const { apiDefaultTxSudo } = useApi();
   const { className, isDisabled, isError, label, onEnter, onEscape, style, withLabel } = props;
 
@@ -46,3 +46,5 @@ export default function ProposalDisplay (props: Props): React.ReactElement<Props
     />
   );
 }
+
+export default React.memo(ProposalDisplay);

+ 3 - 1
packages/react-components/src/Password.tsx

@@ -30,7 +30,7 @@ interface Props extends BareProps {
   withLabel?: boolean;
 }
 
-export default function Password ({ autoFocus, children, className, defaultValue, help, isDisabled, isError, isFull, label, labelExtra, name, onChange, onEnter, onEscape, style, tabIndex, value, withLabel }: Props): React.ReactElement<Props> {
+function Password ({ autoFocus, children, className, defaultValue, help, isDisabled, isError, isFull, label, labelExtra, name, onChange, onEnter, onEscape, style, tabIndex, value, withLabel }: Props): React.ReactElement<Props> {
   const [isVisible, setIsVisible] = useState(false);
 
   const _toggleVisible = (): void => setIsVisible(!isVisible);
@@ -74,3 +74,5 @@ export default function Password ({ autoFocus, children, className, defaultValue
     </Input>
   );
 }
+
+export default React.memo(Password);

+ 3 - 1
packages/react-components/src/Progress.tsx

@@ -22,7 +22,7 @@ interface Props extends BareProps {
   value?: UInt | BN | number;
 }
 
-export default function Progress ({ className, color = 'blue', percent, total, style, value }: Props): React.ReactElement<Props> | null {
+function Progress ({ className, color = 'blue', percent, total, style, value }: Props): React.ReactElement<Props> | null {
   let calculated: number | undefined;
   const _total = bnToBn(total);
   const _value = bnToBn(value);
@@ -61,3 +61,5 @@ export default function Progress ({ className, color = 'blue', percent, total, s
     />
   );
 }
+
+export default React.memo(Progress);

+ 3 - 1
packages/react-components/src/Static.tsx

@@ -20,7 +20,7 @@ interface Props extends BareProps {
   withLabel?: boolean;
 }
 
-export default function Static ({ className, children, defaultValue, help, isHidden, label, style, value, withLabel }: Props): React.ReactElement<Props> {
+function Static ({ className, children, defaultValue, help, isHidden, label, style, value, withLabel }: Props): React.ReactElement<Props> {
   return (
     <Labelled
       className={className}
@@ -37,3 +37,5 @@ export default function Static ({ className, children, defaultValue, help, isHid
     </Labelled>
   );
 }
+
+export default React.memo(Static);

+ 3 - 1
packages/react-components/src/Status/Queue.tsx

@@ -26,7 +26,7 @@ let nextId = 0;
 const REMOVE_TIMEOUT = 7500;
 const SUBMIT_RPC = jsonrpc.author.methods.submitAndWatchExtrinsic;
 
-export default function Queue ({ children }: Props): React.ReactElement<Props> {
+function Queue ({ children }: Props): React.ReactElement<Props> {
   const [_stqueue, _setStQueue] = useState<QueueStatus[]>([]);
   const [_txqueue, _setTxQueue] = useState<QueueTx[]>([]);
   const stRef = useRef(_stqueue);
@@ -183,3 +183,5 @@ export default function Queue ({ children }: Props): React.ReactElement<Props> {
     </QueueProvider>
   );
 }
+
+export default React.memo(Queue);

+ 5 - 6
packages/react-components/src/Table.tsx

@@ -16,10 +16,9 @@ type HeadProps = BaseProps;
 
 type TableProps = BaseProps;
 
-interface TableImpl {
-  (props: TableProps): React.ReactElement<TableProps>;
-  Body: (props: BodyProps) => React.ReactElement<BodyProps>;
-  Head: (props: HeadProps) => React.ReactElement<HeadProps>;
+type TableImpl = React.FC<TableProps> & {
+  Body: React.FC<BodyProps>;
+  Head: React.FC<HeadProps>;
 }
 
 function Head ({ children, className }: HeadProps): React.ReactElement<HeadProps> {
@@ -196,7 +195,7 @@ const Memo = React.memo(styled(Table)`
   }
 `) as unknown as TableImpl;
 
-Memo.Body = Body;
-Memo.Head = Head;
+Memo.Body = React.memo(Body);
+Memo.Head = React.memo(Head);
 
 export default Memo;

+ 3 - 1
packages/react-components/src/Tabs.tsx

@@ -61,7 +61,7 @@ function renderItem ({ basePath, isSequence, items }: Props): (tabItem: TabItem,
   };
 }
 
-export default function Tabs (props: Props): React.ReactElement<Props> {
+function Tabs (props: Props): React.ReactElement<Props> {
   const { className, hidden = [], items, style } = props;
 
   return (
@@ -76,3 +76,5 @@ export default function Tabs (props: Props): React.ReactElement<Props> {
     </div>
   );
 }
+
+export default React.memo(Tabs);

+ 3 - 1
packages/react-components/src/TreasuryProposal.tsx

@@ -23,7 +23,7 @@ interface Props {
   withLink?: boolean;
 }
 
-export default function TreasuryProposal ({ className, asInset, insetProps, onClick, proposal, proposalId }: Props): React.ReactElement<Props> | null {
+function TreasuryProposal ({ className, asInset, insetProps, onClick, proposal, proposalId }: Props): React.ReactElement<Props> | null {
   const { t } = useTranslation();
   const [stateProposal, setProposal] = useState<TreasuryProposalType | null>(null);
   const { api } = useApi();
@@ -93,3 +93,5 @@ export default function TreasuryProposal ({ className, asInset, insetProps, onCl
     </div>
   );
 }
+
+export default React.memo(TreasuryProposal);

+ 3 - 1
packages/react-components/src/TxButton.tsx

@@ -13,7 +13,7 @@ import Button from './Button';
 import { StatusContext } from './Status';
 import { useTranslation } from './translate';
 
-export default function TxButton ({ accountId, className, extrinsic: propsExtrinsic, icon, iconSize, isBasic, isDisabled, isNegative, isPrimary, isUnsigned, label, onClick, onFailed, onSendRef, onStart, onSuccess, onUpdate, params, tx, tooltip, withSpinner }: Props): React.ReactElement<Props> {
+function TxButton ({ accountId, className, extrinsic: propsExtrinsic, icon, iconSize, isBasic, isDisabled, isNegative, isPrimary, isUnsigned, label, onClick, onFailed, onSendRef, onStart, onSuccess, onUpdate, params, tx, tooltip, withSpinner }: Props): React.ReactElement<Props> {
   const { t } = useTranslation();
   const { api } = useApi();
   const { queueExtrinsic } = useContext(StatusContext);
@@ -92,3 +92,5 @@ export default function TxButton ({ accountId, className, extrinsic: propsExtrin
     />
   );
 }
+
+export default React.memo(TxButton);

+ 3 - 1
packages/react-components/src/VoteAccount.tsx

@@ -13,7 +13,7 @@ interface Props {
   onChange: (value: string | null) => void;
 }
 
-export default function VoteAccount ({ className, filter, onChange }: Props): React.ReactElement<Props> {
+function VoteAccount ({ className, filter, onChange }: Props): React.ReactElement<Props> {
   const { t } = useTranslation();
 
   return (
@@ -28,3 +28,5 @@ export default function VoteAccount ({ className, filter, onChange }: Props): Re
     />
   );
 }
+
+export default React.memo(VoteAccount);

+ 3 - 1
packages/react-components/src/VoteActions.tsx

@@ -17,7 +17,7 @@ interface Props {
   tx: string;
 }
 
-export default function VoteActions ({ accountId, className, isDisabled, onClick, params, tx }: Props): React.ReactElement<Props> {
+function VoteActions ({ accountId, className, isDisabled, onClick, params, tx }: Props): React.ReactElement<Props> {
   const { t } = useTranslation();
 
   return (
@@ -38,3 +38,5 @@ export default function VoteActions ({ accountId, className, isDisabled, onClick
     </Modal.Actions>
   );
 }
+
+export default React.memo(VoteActions);

+ 3 - 1
packages/react-components/src/VoteToggle.tsx

@@ -13,7 +13,7 @@ interface Props {
   value: boolean;
 }
 
-export default function VoteToggle ({ className, onChange, value }: Props): React.ReactElement<Props> {
+function VoteToggle ({ className, onChange, value }: Props): React.ReactElement<Props> {
   const { t } = useTranslation();
   const voteOpts = useMemo(() => [
     { text: t('Aye, I approve'), value: true },
@@ -31,3 +31,5 @@ export default function VoteToggle ({ className, onChange, value }: Props): Reac
     />
   );
 }
+
+export default React.memo(VoteToggle);

+ 12 - 3
packages/react-components/src/styles/index.ts

@@ -75,6 +75,13 @@ export default createGlobalStyle<Props>`
         background-color: ${(props): string => (props.uiHighlight || defaultHighlight)};
       }
     }
+
+    .ui.toggle.checkbox {
+      input:checked~.box:before,
+      input:checked~label:before {
+        background-color: ${(props): string => (props.uiHighlight || defaultHighlight)} !important;
+      }
+    }
   }
 
   #root {
@@ -109,9 +116,11 @@ export default createGlobalStyle<Props>`
         color: #555 !important;
       }
 
-      .ui.toggle.checkbox input:checked~.box:before,
-      .ui.toggle.checkbox input:checked~label:before {
-        background-color: #eee !important;
+      .ui.toggle.checkbox {
+        input:checked~.box:before,
+        input:checked~label:before {
+          background-color: #eee !important;
+        }
       }
 
       .ui.button.mini {

+ 1 - 1
packages/react-components/src/styles/theme.ts

@@ -103,7 +103,7 @@ export default css`
 
     .ui.toggle.checkbox input:checked~.box:before,
     .ui.toggle.checkbox input:checked~label:before {
-      background-color: ${colorBtnHighlight} !important;
+      // background-color: ${colorBtnHighlight} !important;
     }
   }
 `;