Created
July 29, 2022 07:27
-
-
Save gkanishk/fffc2c214f4e39d1210c73beabc0c9e4 to your computer and use it in GitHub Desktop.
viewrenderer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import * as React from 'react'; | |
| import { CSSProperties } from 'react'; | |
| import { Dimension } from '../../../core/dependencies/LayoutProvider'; | |
| import BaseViewRenderer, { ViewRendererProps } from '../../../core/viewrenderer/BaseViewRenderer'; | |
| /*** | |
| * View renderer is responsible for creating a container of size provided by LayoutProvider and render content inside it. | |
| * Also enforces a logic to prevent re renders. RecyclerListView keeps moving these ViewRendereres around using transforms to enable recycling. | |
| * View renderer will only update if its position, dimensions or given data changes. Make sure to have a relevant shouldComponentUpdate as well. | |
| * This is second of the two things recycler works on. Implemented both for web and react native. | |
| */ | |
| export default class ViewRenderer extends BaseViewRenderer<any> { | |
| private _dim: Dimension = { width: 0, height: 0 }; | |
| private _mainDiv: HTMLDivElement | null = null; | |
| private _sizeObserver?: ResizeObserver; | |
| private _isPendingSizeUpdate: boolean = false; | |
| public componentDidMount(): void { | |
| super.componentDidMount(); | |
| this._checkSizeChange(); | |
| if (!this._sizeObserver && ResizeObserver) { | |
| this._sizeObserver = new ResizeObserver(() => { | |
| this._checkSizeChange(true); | |
| }); | |
| if (this._mainDiv) { | |
| this._sizeObserver.observe(this._mainDiv); | |
| } | |
| } | |
| } | |
| public componentDidUpdate(): void { | |
| this._isPendingSizeUpdate = false; | |
| this._checkSizeChange(); | |
| } | |
| public componentWillUnmount(): void { | |
| super.componentWillUnmount(); | |
| if (this._sizeObserver) { | |
| this._sizeObserver.disconnect(); | |
| this._sizeObserver = undefined; | |
| } | |
| } | |
| public renderCompat(): JSX.Element { | |
| const style: CSSProperties = this.props.forceNonDeterministicRendering | |
| ? { | |
| transform: this._getTransform(), | |
| WebkitTransform: this._getTransform(), | |
| ...styles.baseViewStyle, | |
| ...this.props.styleOverrides, | |
| ...this.animatorStyleOverrides, | |
| } | |
| : { | |
| height: this.props.height, | |
| overflow: 'hidden', | |
| width: this.props.width, | |
| transform: this._getTransform(), | |
| WebkitTransform: this._getTransform(), | |
| ...styles.baseViewStyle, | |
| ...this.props.styleOverrides, | |
| ...this.animatorStyleOverrides, | |
| }; | |
| const props = { | |
| style, | |
| ref: this._setRef, | |
| }; | |
| return this._renderItemContainer(props, this.props, this.renderChild()) as JSX.Element; | |
| } | |
| protected getRef(): object | null { | |
| return this._mainDiv; | |
| } | |
| private _renderItemContainer(props: object, parentProps: ViewRendererProps<any>, children: React.ReactNode): React.ReactNode { | |
| return (this.props.renderItemContainer && this.props.renderItemContainer(props, parentProps, children)) || <div {...props}>{children}</div>; | |
| } | |
| private _setRef = (div: HTMLDivElement | null): void => { | |
| this._mainDiv = div; | |
| }; | |
| private _getTransform(): string { | |
| return 'translate(' + this.props.x + 'px,' + this.props.y + 'px)'; | |
| } | |
| private _checkSizeChange(fromObserver: boolean = false): void { | |
| if (this.props.forceNonDeterministicRendering && this.props.onSizeChanged) { | |
| const mainDiv = this._mainDiv; | |
| if (mainDiv) { | |
| this._dim.width = mainDiv.clientWidth; | |
| this._dim.height = mainDiv.clientHeight; | |
| if (this.props.width !== this._dim.width || this.props.height !== this._dim.height) { | |
| this._isPendingSizeUpdate = true; | |
| this.props.onSizeChanged(this._dim, this.props.index); | |
| } else if (fromObserver && this._isPendingSizeUpdate) { | |
| this.props.onSizeChanged(this._dim, this.props.index); | |
| } | |
| } | |
| } | |
| this._onItemRendered(); | |
| } | |
| private _onItemRendered(): void { | |
| if (this.props.onItemLayout) { | |
| this.props.onItemLayout(this.props.index); | |
| } | |
| } | |
| } | |
| const styles: { [key: string]: CSSProperties } = { | |
| baseViewStyle: { | |
| alignItems: 'stretch', | |
| borderWidth: 0, | |
| borderStyle: 'solid', | |
| boxSizing: 'border-box', | |
| display: 'flex', | |
| flexDirection: 'column', | |
| margin: 0, | |
| padding: 0, | |
| position: 'absolute', | |
| minHeight: 0, | |
| minWidth: 0, | |
| left: 0, | |
| top: 0, | |
| }, | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment