Make Tooltip as a function component with react hooks (#391)

* Refactor `Tooltip` into function component with hooks

With using hooks, we don't need to maintain the checking in sCU and also
don't need to assign the value of `ref` manually.

* Show block number beside the tooltip instead of its children
This commit is contained in:
cybai authored and GitHub committed 2021-09-09 13:02:10 +02:00
1 parent fe19a75414
commit 3ea2f88b19
2 files changed
+52 -61

No files matched your search

@@ -125,9 +125,8 @@ export class ConsensusBlock extends React.Component<ConsensusBlock.Props, {}> {
className="legend" className="legend"
key={'block_row_' + this.props.height + '_legend'} key={'block_row_' + this.props.height + '_legend'}
> >
<Tooltip text={`Block number: ${this.props.height}`}> <Tooltip text={`Block number: ${this.props.height}`} />
{this.displayBlockNumber()} {this.displayBlockNumber()}
</Tooltip>
</th> </th>
<th <th
className="finalizedInfo" className="finalizedInfo"
+51 -59
View File
@@ -23,7 +23,6 @@ export namespace Tooltip {
export interface Props { export interface Props {
text: string; text: string;
copy?: (cb: CopyCallback) => void; copy?: (cb: CopyCallback) => void;
className?: string;
position?: 'left' | 'right' | 'center'; position?: 'left' | 'right' | 'center';
onInit?: (update: UpdateCallback) => void; onInit?: (update: UpdateCallback) => void;
} }
@@ -45,43 +44,61 @@ function copyToClipboard(text: string) {
document.body.removeChild(el); document.body.removeChild(el);
} }
export class Tooltip extends React.Component<Tooltip.Props, Tooltip.State> { export function Tooltip({
public state = { copied: false }; text,
position,
copy,
onInit,
}: Tooltip.Props): JSX.Element {
const [copied, setCopied] = React.useState<boolean>(false);
const [timer, setTimer] = React.useState<NodeJS.Timer | null>(null);
const el = React.useRef<HTMLDivElement>(null);
private el: HTMLDivElement; const update = React.useCallback(
private timer: NodeJS.Timer | null = null; (newText: string) => {
if (el.current) {
public componentDidMount() { el.current.textContent = newText;
if (this.props.onInit) {
this.props.onInit(this.update);
} }
if (this.props.copy) { },
this.props.copy(this.onClick); [el]
}
}
public componentWillUnmount() {
if (this.timer) {
clearTimeout(this.timer);
}
if (this.props.copy) {
this.props.copy(null);
}
}
public shouldComponentUpdate(
nextProps: Tooltip.Props,
nextState: Tooltip.State
) {
return (
this.props.text !== nextProps.text ||
this.state.copied !== nextState.copied
); );
function restore() {
setCopied(false);
setTimer(null);
} }
public render() { function onClick() {
const { text, className, position } = this.props; copyToClipboard(text);
const { copied } = this.state;
if (timer) {
clearTimeout(timer);
}
setCopied(true);
setTimer(setTimeout(restore, 2000));
}
React.useEffect(() => {
if (onInit) {
onInit(update);
}
if (copy) {
copy(onClick);
}
return () => {
if (timer) {
clearTimeout(timer);
}
if (copy) {
copy(null);
}
};
}, []);
let tooltipClass = 'Tooltip'; let tooltipClass = 'Tooltip';
@@ -94,33 +111,8 @@ export class Tooltip extends React.Component<Tooltip.Props, Tooltip.State> {
} }
return ( return (
<div className={tooltipClass} ref={this.onRef}> <div className={tooltipClass} ref={el}>
{copied ? 'Copied to clipboard!' : text} {copied ? 'Copied to clipboard!' : text}
</div> </div>
); );
} }
private onRef = (el: HTMLDivElement) => {
this.el = el;
};
private update = (text: string) => {
this.el.textContent = text;
};
private onClick = () => {
copyToClipboard(this.props.text);
if (this.timer) {
clearTimeout(this.timer);
}
this.setState({ copied: true });
this.timer = setTimeout(this.restore, 2000);
};
private restore = () => {
this.setState({ copied: false });
this.timer = null;
};
}