Skip to content

Commit

Permalink
improve perf of highlighting same address in lists (#1662)
Browse files Browse the repository at this point in the history
Fixes #1661
  • Loading branch information
tom2drum authored Mar 4, 2024
1 parent 82b7f3d commit 20d8c0c
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 28 deletions.
21 changes: 15 additions & 6 deletions lib/contexts/addressHighlight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,47 @@ interface AddressHighlightProviderProps {
}

interface TAddressHighlightContext {
highlightedAddress: string | null;
onMouseEnter: (event: React.MouseEvent) => void;
onMouseLeave: (event: React.MouseEvent) => void;
}

export const AddressHighlightContext = React.createContext<TAddressHighlightContext | null>(null);

export function AddressHighlightProvider({ children }: AddressHighlightProviderProps) {
const [ highlightedAddress, setHighlightedAddress ] = React.useState<string | null>(null);
const timeoutId = React.useRef<number | null>(null);
const hashRef = React.useRef<string | null>(null);

const onMouseEnter = React.useCallback((event: React.MouseEvent) => {
const hash = event.currentTarget.getAttribute('data-hash');
if (hash) {
hashRef.current = hash;
timeoutId.current = window.setTimeout(() => {
setHighlightedAddress(hash);
// for better performance we update DOM-nodes directly bypassing React reconciliation
const nodes = window.document.querySelectorAll(`[data-hash="${ hashRef.current }"]`);
for (const node of nodes) {
node.classList.add('address-entity_highlighted');
}
}, 100);
}
}, []);

const onMouseLeave = React.useCallback(() => {
setHighlightedAddress(null);
if (hashRef.current) {
const nodes = window.document.querySelectorAll(`[data-hash="${ hashRef.current }"]`);
for (const node of nodes) {
node.classList.remove('address-entity_highlighted');
}
hashRef.current = null;
}
typeof timeoutId.current === 'number' && window.clearTimeout(timeoutId.current);
}, []);

const value = React.useMemo(() => {
return {
highlightedAddress,
onMouseEnter,
onMouseLeave,
};
}, [ highlightedAddress, onMouseEnter, onMouseLeave ]);
}, [ onMouseEnter, onMouseLeave ]);

React.useEffect(() => {
return () => {
Expand Down
2 changes: 2 additions & 0 deletions theme/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { mode } from '@chakra-ui/theme-tools';

import scrollbar from './foundations/scrollbar';
import addressEntity from './globals/address-entity';
import getDefaultTransitionProps from './utils/getDefaultTransitionProps';

const global = (props: StyleFunctionProps) => ({
Expand All @@ -23,6 +24,7 @@ const global = (props: StyleFunctionProps) => ({
w: '100%',
},
...scrollbar(props),
...addressEntity(props),
});

export default global;
37 changes: 37 additions & 0 deletions theme/globals/address-entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { mode } from '@chakra-ui/theme-tools';
import type { StyleFunctionProps } from '@chakra-ui/theme-tools';

const styles = (props: StyleFunctionProps) => {
return {
'.address-entity': {
'&.address-entity_highlighted': {
_before: {
content: `" "`,
position: 'absolute',
py: 1,
pl: 1,
pr: 0,
top: '-5px',
left: '-5px',
width: `100%`,
height: '100%',
borderRadius: 'base',
borderColor: mode('blue.200', 'blue.600')(props),
borderWidth: '1px',
borderStyle: 'dashed',
bgColor: mode('blue.50', 'blue.900')(props),
zIndex: -1,
},
},
},
'.address-entity_no-copy': {
'&.address-entity_highlighted': {
_before: {
pr: 2,
},
},
},
};
};

export default styles;
27 changes: 5 additions & 22 deletions ui/shared/entities/address/AddressEntity.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { As } from '@chakra-ui/react';
import { Box, Flex, Skeleton, Tooltip, chakra, VStack, useColorModeValue } from '@chakra-ui/react';
import { Box, Flex, Skeleton, Tooltip, chakra, VStack } from '@chakra-ui/react';
import _omit from 'lodash/omit';
import React from 'react';

Expand Down Expand Up @@ -148,33 +148,16 @@ const AddressEntry = (props: EntityProps) => {
const partsProps = _omit(props, [ 'className', 'onClick' ]);

const context = useAddressHighlightContext();
const highlightedBgColor = useColorModeValue('blue.50', 'blue.900');
const highlightedBorderColor = useColorModeValue('blue.200', 'blue.600');

return (
<Container
className={ props.className }
data-hash={ props.address.hash }
// we have to use the global classnames here, see theme/global.ts
// otherwise, if we use sx prop, Chakra will generate the same styles for each instance of the component on the page
className={ `${ props.className } address-entity ${ props.noCopy ? 'address-entity_no-copy' : '' }` }
data-hash={ context && !props.isLoading ? props.address.hash : undefined }
onMouseEnter={ context?.onMouseEnter }
onMouseLeave={ context?.onMouseLeave }
position="relative"
_before={ !props.isLoading && context?.highlightedAddress === props.address.hash ? {
content: `" "`,
position: 'absolute',
py: 1,
pl: 1,
pr: props.noCopy ? 2 : 0,
top: '-5px',
left: '-5px',
width: `100%`,
height: '100%',
borderRadius: 'base',
borderColor: highlightedBorderColor,
borderWidth: '1px',
borderStyle: 'dashed',
bgColor: highlightedBgColor,
zIndex: -1,
} : undefined }
>
<Icon { ...partsProps }/>
<Link { ...linkProps }>
Expand Down

0 comments on commit 20d8c0c

Please sign in to comment.