Fix redraw after resizing elements
Summary: Fixed a longer standing issue where after a horizontal resize the rows wouldn't redraw until new data arrives (or the user scrolls), resulting in rendering artefacts. Also introduced a hook to force a reflow of contents if the contents of a hook changes. It's a bit leaky abstraction, but does keep the virtualization performant if dynamic heights are used. Reviewed By: passy Differential Revision: D27395516 fbshipit-source-id: 1691af3ec64f1a476969a318553d83e22239997c
This commit is contained in:
committed by
Facebook GitHub Bot
parent
b597da01e7
commit
8cd38a6b49
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@emotion/css": "^11.1.3",
|
||||
"@emotion/react": "^11.1.5",
|
||||
"@reach/observe-rect": "^1.2.0",
|
||||
"immer": "^9.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"react-element-to-jsx-string": "^14.3.2",
|
||||
|
||||
@@ -15,10 +15,11 @@ import {
|
||||
import {Button, Typography} from 'antd';
|
||||
import {pad} from 'lodash';
|
||||
import React, {createElement, Fragment, isValidElement, useState} from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import {tryGetFlipperLibImplementation} from '../plugin/FlipperLib';
|
||||
import {safeStringify} from '../utils/safeStringify';
|
||||
import {urlRegex} from '../utils/urlRegex';
|
||||
import {useTableRedraw} from './datatable/DataSourceRenderer';
|
||||
import {theme} from './theme';
|
||||
|
||||
/**
|
||||
* A Formatter is used to render an arbitrarily value to React. If a formatter returns 'undefined'
|
||||
@@ -136,7 +137,7 @@ export const DataFormatter = {
|
||||
},
|
||||
};
|
||||
|
||||
const TruncateHelper = styled(function TruncateHelper({
|
||||
function TruncateHelper({
|
||||
value,
|
||||
maxLength,
|
||||
}: {
|
||||
@@ -144,29 +145,37 @@ const TruncateHelper = styled(function TruncateHelper({
|
||||
maxLength: number;
|
||||
}) {
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const redrawRow = useTableRedraw();
|
||||
|
||||
return (
|
||||
<>
|
||||
{collapsed ? value.substr(0, maxLength) : value}
|
||||
<Button
|
||||
onClick={() => setCollapsed((c) => !c)}
|
||||
onClick={() => {
|
||||
setCollapsed((c) => !c);
|
||||
redrawRow?.();
|
||||
}}
|
||||
size="small"
|
||||
type="text"
|
||||
style={truncateButtonStyle}
|
||||
icon={collapsed ? <CaretRightOutlined /> : <CaretUpOutlined />}>
|
||||
{`(and ${value.length - maxLength} more...)`}
|
||||
</Button>
|
||||
<Button
|
||||
icon={<CopyOutlined />}
|
||||
onClick={() =>
|
||||
tryGetFlipperLibImplementation()?.writeTextToClipboard(value)
|
||||
}
|
||||
onClick={() => {
|
||||
tryGetFlipperLibImplementation()?.writeTextToClipboard(value);
|
||||
}}
|
||||
size="small"
|
||||
type="text">
|
||||
type="text"
|
||||
style={truncateButtonStyle}>
|
||||
Copy
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
})({
|
||||
'& button': {
|
||||
marginRight: 4,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const truncateButtonStyle = {
|
||||
color: theme.textColorPrimary,
|
||||
marginLeft: 4,
|
||||
};
|
||||
|
||||
@@ -15,10 +15,13 @@ import React, {
|
||||
useState,
|
||||
useLayoutEffect,
|
||||
MutableRefObject,
|
||||
useContext,
|
||||
createContext,
|
||||
} from 'react';
|
||||
import {DataSource} from '../../state/DataSource';
|
||||
import {useVirtual} from 'react-virtual';
|
||||
import styled from '@emotion/styled';
|
||||
import observeRect from '@reach/observe-rect';
|
||||
|
||||
// how fast we update if updates are low-prio (e.g. out of window and not super significant)
|
||||
const LOW_PRIO_UPDATE = 1000; //ms
|
||||
@@ -92,9 +95,8 @@ export const DataSourceRenderer: <T extends object, C>(
|
||||
// render scheduling
|
||||
const renderPending = useRef(UpdatePrio.NONE);
|
||||
const lastRender = useRef(Date.now());
|
||||
const setForceUpdate = useState(0)[1];
|
||||
const [, setForceUpdate] = useState(0);
|
||||
const forceHeightRecalculation = useRef(0);
|
||||
|
||||
const parentRef = React.useRef<null | HTMLDivElement>(null);
|
||||
|
||||
const virtualizer = useVirtual({
|
||||
@@ -111,6 +113,11 @@ export const DataSourceRenderer: <T extends object, C>(
|
||||
virtualizerRef.current = virtualizer;
|
||||
}
|
||||
|
||||
const redraw = useCallback(() => {
|
||||
forceHeightRecalculation.current++;
|
||||
setForceUpdate((x) => x + 1);
|
||||
}, []);
|
||||
|
||||
useEffect(
|
||||
function subscribeToDataSource() {
|
||||
const forceUpdate = () => {
|
||||
@@ -261,10 +268,33 @@ export const DataSourceRenderer: <T extends object, C>(
|
||||
lastRender.current = Date.now();
|
||||
});
|
||||
|
||||
/**
|
||||
* Observer parent height
|
||||
*/
|
||||
useEffect(
|
||||
function redrawOnResize() {
|
||||
if (!parentRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
let lastWidth = 0;
|
||||
const observer = observeRect(parentRef.current, (rect) => {
|
||||
if (lastWidth !== rect.width) {
|
||||
lastWidth = rect.width;
|
||||
redraw();
|
||||
}
|
||||
});
|
||||
observer.observe();
|
||||
return () => observer.unobserve();
|
||||
},
|
||||
[redraw],
|
||||
);
|
||||
|
||||
/**
|
||||
* Rendering
|
||||
*/
|
||||
return (
|
||||
<RedrawContext.Provider value={redraw}>
|
||||
<TableContainer onScroll={onScroll} ref={parentRef}>
|
||||
{virtualizer.virtualItems.length === 0
|
||||
? emptyRenderer?.(dataSource)
|
||||
@@ -295,6 +325,7 @@ export const DataSourceRenderer: <T extends object, C>(
|
||||
})}
|
||||
</TableWindow>
|
||||
</TableContainer>
|
||||
</RedrawContext.Provider>
|
||||
);
|
||||
}) as any;
|
||||
|
||||
@@ -310,3 +341,9 @@ const TableWindow = styled.div<{height: number}>(({height}) => ({
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
}));
|
||||
|
||||
export const RedrawContext = createContext<undefined | (() => void)>(undefined);
|
||||
|
||||
export function useTableRedraw() {
|
||||
return useContext(RedrawContext);
|
||||
}
|
||||
|
||||
@@ -2150,7 +2150,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@oclif/screen/-/screen-1.0.4.tgz#b740f68609dfae8aa71c3a6cab15d816407ba493"
|
||||
integrity sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw==
|
||||
|
||||
"@reach/observe-rect@^1.1.0":
|
||||
"@reach/observe-rect@^1.1.0", "@reach/observe-rect@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@reach/observe-rect/-/observe-rect-1.2.0.tgz#d7a6013b8aafcc64c778a0ccb83355a11204d3b2"
|
||||
integrity sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ==
|
||||
|
||||
Reference in New Issue
Block a user