Convert LazyRenderList TS

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
Šimon Brandner 2021-09-15 20:44:26 +02:00
parent 1ee606c693
commit 9e2bc28c06
No known key found for this signature in database
GPG key ID: 55C211A1226CB17D

View file

@ -15,17 +15,16 @@ limitations under the License.
*/ */
import React from "react"; import React from "react";
import PropTypes from 'prop-types';
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
class ItemRange { class ItemRange {
constructor(topCount, renderCount, bottomCount) { constructor(
this.topCount = topCount; public topCount: number,
this.renderCount = renderCount; public renderCount: number,
this.bottomCount = bottomCount; public bottomCount: number,
} ) { }
contains(range) { public contains(range: ItemRange): boolean {
// don't contain empty ranges // don't contain empty ranges
// as it will prevent clearing the list // as it will prevent clearing the list
// once it is scrolled far enough out of view // once it is scrolled far enough out of view
@ -36,7 +35,7 @@ class ItemRange {
(range.topCount + range.renderCount) <= (this.topCount + this.renderCount); (range.topCount + range.renderCount) <= (this.topCount + this.renderCount);
} }
expand(amount) { public expand(amount: number): ItemRange {
// don't expand ranges that won't render anything // don't expand ranges that won't render anything
if (this.renderCount === 0) { if (this.renderCount === 0) {
return this; return this;
@ -51,20 +50,55 @@ class ItemRange {
); );
} }
totalSize() { public totalSize(): number {
return this.topCount + this.renderCount + this.bottomCount; return this.topCount + this.renderCount + this.bottomCount;
} }
} }
interface IProps<T extends unknown> {
// height in pixels of the component returned by `renderItem`
itemHeight: number;
// function to turn an element of `items` into a react component
renderItem: (item: T) => JSX.Element;
// scrollTop of the viewport (minus the height of any content above this list like other `LazyRenderList`s)
scrollTop: number;
// the height of the viewport this content is scrolled in
height: number;
// all items for the list. These should not be react components, see `renderItem`.
items?: T[];
// the amount of items to scroll before causing a rerender,
// should typically be less than `overflowItems` unless applying
// margins in the parent component when using multiple LazyRenderList in one viewport.
// use 0 to only rerender when items will come into view.
overflowMargin?: number;
// the amount of items to add at the top and bottom to render,
// so not every scroll of causes a rerender.
overflowItems?: number;
element?: string;
className?: string;
}
interface IState {
renderRange: ItemRange;
}
@replaceableComponent("views.elements.LazyRenderList") @replaceableComponent("views.elements.LazyRenderList")
export default class LazyRenderList extends React.Component { export default class LazyRenderList extends React.Component<IProps<unknown>, IState> {
constructor(props) { public static defaultProps: Partial<IProps<unknown>> = {
overflowItems: 20,
overflowMargin: 5,
};
constructor(props: IProps<unknown>) {
super(props); super(props);
this.state = {}; this.state = {
renderRange: null,
};
} }
static getDerivedStateFromProps(props, state) { public static getDerivedStateFromProps(props: IProps<unknown>, state: IState): Partial<IState> {
const range = LazyRenderList.getVisibleRangeFromProps(props); const range = LazyRenderList.getVisibleRangeFromProps(props);
const intersectRange = range.expand(props.overflowMargin); const intersectRange = range.expand(props.overflowMargin);
const renderRange = range.expand(props.overflowItems); const renderRange = range.expand(props.overflowItems);
@ -77,7 +111,7 @@ export default class LazyRenderList extends React.Component {
return null; return null;
} }
static getVisibleRangeFromProps(props) { private static getVisibleRangeFromProps(props: IProps<unknown>): ItemRange {
const { items, itemHeight, scrollTop, height } = props; const { items, itemHeight, scrollTop, height } = props;
const length = items ? items.length : 0; const length = items ? items.length : 0;
const topCount = Math.min(Math.max(0, Math.floor(scrollTop / itemHeight)), length); const topCount = Math.min(Math.max(0, Math.floor(scrollTop / itemHeight)), length);
@ -88,7 +122,7 @@ export default class LazyRenderList extends React.Component {
return new ItemRange(topCount, renderCount, bottomCount); return new ItemRange(topCount, renderCount, bottomCount);
} }
render() { public render(): JSX.Element {
const { itemHeight, items, renderItem } = this.props; const { itemHeight, items, renderItem } = this.props;
const { renderRange } = this.state; const { renderRange } = this.state;
const { topCount, renderCount, bottomCount } = renderRange; const { topCount, renderCount, bottomCount } = renderRange;
@ -109,28 +143,3 @@ export default class LazyRenderList extends React.Component {
} }
} }
LazyRenderList.defaultProps = {
overflowItems: 20,
overflowMargin: 5,
};
LazyRenderList.propTypes = {
// height in pixels of the component returned by `renderItem`
itemHeight: PropTypes.number.isRequired,
// function to turn an element of `items` into a react component
renderItem: PropTypes.func.isRequired,
// scrollTop of the viewport (minus the height of any content above this list like other `LazyRenderList`s)
scrollTop: PropTypes.number.isRequired,
// the height of the viewport this content is scrolled in
height: PropTypes.number.isRequired,
// all items for the list. These should not be react components, see `renderItem`.
items: PropTypes.array,
// the amount of items to scroll before causing a rerender,
// should typically be less than `overflowItems` unless applying
// margins in the parent component when using multiple LazyRenderList in one viewport.
// use 0 to only rerender when items will come into view.
overflowMargin: PropTypes.number,
// the amount of items to add at the top and bottom to render,
// so not every scroll of causes a rerender.
overflowItems: PropTypes.number,
};