mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-01-18 18:55:54 +08:00
Use virtualized list
This commit is contained in:
parent
99f147df66
commit
f31f248937
@ -56,6 +56,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-window": "1.8.5",
|
||||
"redux-devtools": "3.7.0"
|
||||
},
|
||||
"homepage": "/[[.RootPath]]"
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from "react";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { makeStyles, useTheme } from "@material-ui/core/styles";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Autocomplete from "@material-ui/lab/Autocomplete";
|
||||
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
||||
import ListSubheader from "@material-ui/core/ListSubheader";
|
||||
import { VariableSizeList, ListChildComponentProps } from "react-window";
|
||||
import { GroupInfo } from "../api";
|
||||
import { isDarkTheme } from "../theme";
|
||||
|
||||
@ -34,6 +37,12 @@ export default function GroupSelect(props: Props) {
|
||||
return (
|
||||
<Autocomplete
|
||||
id="task-group-selector"
|
||||
disableListWrap
|
||||
ListboxComponent={
|
||||
ListboxComponent as React.ComponentType<
|
||||
React.HTMLAttributes<HTMLElement>
|
||||
>
|
||||
}
|
||||
options={props.groups}
|
||||
getOptionLabel={(option: GroupInfo) => option.group}
|
||||
style={{ width: 300 }}
|
||||
@ -49,3 +58,83 @@ export default function GroupSelect(props: Props) {
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Virtualized list.
|
||||
// Reference: https://v4.mui.com/components/autocomplete/#virtualization
|
||||
|
||||
const LISTBOX_PADDING = 8; // px
|
||||
|
||||
function renderRow(props: ListChildComponentProps) {
|
||||
const { data, index, style } = props;
|
||||
return React.cloneElement(data[index], {
|
||||
style: {
|
||||
...style,
|
||||
top: (style.top as number) + LISTBOX_PADDING,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const OuterElementContext = React.createContext({});
|
||||
|
||||
const OuterElementType = React.forwardRef<HTMLDivElement>((props, ref) => {
|
||||
const outerProps = React.useContext(OuterElementContext);
|
||||
return <div ref={ref} {...props} {...outerProps} />;
|
||||
});
|
||||
|
||||
function useResetCache(data: any) {
|
||||
const ref = React.useRef<VariableSizeList>(null);
|
||||
React.useEffect(() => {
|
||||
if (ref.current != null) {
|
||||
ref.current.resetAfterIndex(0, true);
|
||||
}
|
||||
}, [data]);
|
||||
return ref;
|
||||
}
|
||||
|
||||
// Adapter for react-window
|
||||
const ListboxComponent = React.forwardRef<HTMLDivElement>(
|
||||
function ListboxComponent(props, ref) {
|
||||
const { children, ...other } = props;
|
||||
const itemData = React.Children.toArray(children);
|
||||
const theme = useTheme();
|
||||
const smUp = useMediaQuery(theme.breakpoints.up("sm"), { noSsr: true });
|
||||
const itemCount = itemData.length;
|
||||
const itemSize = smUp ? 36 : 48;
|
||||
|
||||
const getChildSize = (child: React.ReactNode) => {
|
||||
if (React.isValidElement(child) && child.type === ListSubheader) {
|
||||
return 48;
|
||||
}
|
||||
return itemSize;
|
||||
};
|
||||
|
||||
const getHeight = () => {
|
||||
if (itemCount > 8) {
|
||||
return 8 * itemSize;
|
||||
}
|
||||
return itemData.map(getChildSize).reduce((a, b) => a + b, 0);
|
||||
};
|
||||
|
||||
const gridRef = useResetCache(itemCount);
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<OuterElementContext.Provider value={other}>
|
||||
<VariableSizeList
|
||||
itemData={itemData}
|
||||
height={getHeight() + 2 * LISTBOX_PADDING}
|
||||
width="100%"
|
||||
ref={gridRef}
|
||||
outerElementType={OuterElementType}
|
||||
innerElementType="ul"
|
||||
itemSize={(index) => getChildSize(itemData[index])}
|
||||
overscanCount={5}
|
||||
itemCount={itemCount}
|
||||
>
|
||||
{renderRow}
|
||||
</VariableSizeList>
|
||||
</OuterElementContext.Provider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -2036,6 +2036,13 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-window@1.8.5":
|
||||
version "1.8.5"
|
||||
resolved "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.5.tgz#285fcc5cea703eef78d90f499e1457e9b5c02fc1"
|
||||
integrity sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^17.0.29":
|
||||
version "17.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.29.tgz#9535f3fc01a4981ce9cadcf0daa2593c0c2f2251"
|
||||
|
Loading…
Reference in New Issue
Block a user