Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compat component to maintain compatibility across react version #387

Merged
merged 10 commits into from
Aug 21, 2019
9 changes: 5 additions & 4 deletions src/core/RecyclerListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { TOnItemStatusChanged } from "./ViewabilityTracker";
import VirtualRenderer, { RenderStack, RenderStackItem, RenderStackParams } from "./VirtualRenderer";
import ItemAnimator, { BaseItemAnimator } from "./ItemAnimator";
import { DebugHandlers } from "..";
import { ComponentCompat } from "../utils/ComponentCompat";
//#if [REACT-NATIVE]
import ScrollComponent from "../platform/reactnative/scrollcomponent/ScrollComponent";
import ViewRenderer from "../platform/reactnative/viewrenderer/ViewRenderer";
Expand Down Expand Up @@ -114,7 +115,7 @@ export interface RecyclerListViewState {
internalSnapshot: Record<string, object>;
}

export default class RecyclerListView<P extends RecyclerListViewProps, S extends RecyclerListViewState> extends React.Component<P, S> {
export default class RecyclerListView<P extends RecyclerListViewProps, S extends RecyclerListViewState> extends ComponentCompat<P, S> {
public static defaultProps = {
canChangeSize: false,
disableRecycling: false,
Expand Down Expand Up @@ -166,7 +167,7 @@ export default class RecyclerListView<P extends RecyclerListViewProps, S extends
} as S;
}

public componentWillReceiveProps(newProps: RecyclerListViewProps): void {
public componentWillReceivePropsCompat(newProps: RecyclerListViewProps): void {
this._assertDependencyPresence(newProps);
this._checkAndChangeLayouts(newProps);
if (!this.props.onVisibleIndicesChanged) {
Expand Down Expand Up @@ -219,7 +220,7 @@ export default class RecyclerListView<P extends RecyclerListViewProps, S extends
}
}

public componentWillMount(): void {
public componentWillMountCompat(): void {
if (this.props.contextProvider) {
const uniqueKey = this.props.contextProvider.getUniqueKey();
if (uniqueKey) {
Expand Down Expand Up @@ -334,7 +335,7 @@ export default class RecyclerListView<P extends RecyclerListViewProps, S extends
});
}

public render(): JSX.Element {
public renderCompat(): JSX.Element {
//TODO:Talha
// const {
// layoutProvider,
Expand Down
71 changes: 36 additions & 35 deletions src/core/StickyContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@

import * as React from "react";
import * as PropTypes from "prop-types";
import {StyleProp, View, ViewStyle} from "react-native";
import RecyclerListView, {RecyclerListViewState, RecyclerListViewProps} from "./RecyclerListView";
import {ScrollEvent} from "./scrollcomponent/BaseScrollView";
import StickyObject, {StickyObjectProps, StickyObjectState} from "./sticky/StickyObject";
import { StyleProp, View, ViewStyle } from "react-native";
import RecyclerListView, { RecyclerListViewState, RecyclerListViewProps } from "./RecyclerListView";
import { ScrollEvent } from "./scrollcomponent/BaseScrollView";
import StickyObject, { StickyObjectProps } from "./sticky/StickyObject";
import StickyHeader from "./sticky/StickyHeader";
import StickyFooter from "./sticky/StickyFooter";
import CustomError from "./exceptions/CustomError";
import RecyclerListViewExceptions from "./exceptions/RecyclerListViewExceptions";
import {Layout} from "./layoutmanager/LayoutManager";
import {BaseLayoutProvider, Dimension} from "./dependencies/LayoutProvider";
import { Layout } from "./layoutmanager/LayoutManager";
import { BaseLayoutProvider, Dimension } from "./dependencies/LayoutProvider";
import { BaseDataProvider } from "./dependencies/DataProvider";
import {ReactElement} from "react";
import { ReactElement } from "react";
import { ComponentCompat } from "../utils/ComponentCompat";

export interface StickyContainerProps {
children: RecyclerChild;
Expand All @@ -28,7 +29,7 @@ export interface RecyclerChild extends React.ReactElement<RecyclerListViewProps>
ref: (recyclerRef: any) => {};
props: RecyclerListViewProps;
}
export default class StickyContainer<P extends StickyContainerProps> extends React.Component<P> {
export default class StickyContainer<P extends StickyContainerProps> extends ComponentCompat<P> {
public static propTypes = {};
private _recyclerRef: RecyclerListView<RecyclerListViewProps, RecyclerListViewState> | undefined = undefined;
private _dataProvider: BaseDataProvider;
Expand All @@ -37,8 +38,8 @@ export default class StickyContainer<P extends StickyContainerProps> extends Rea
private _rowRenderer: ((type: string | number, data: any, index: number, extendedState?: object) => JSX.Element | JSX.Element[] | null);
private _distanceFromWindow: number;

private _stickyHeaderRef: StickyHeader<StickyObjectProps, StickyObjectState> | null = null;
private _stickyFooterRef: StickyFooter<StickyObjectProps, StickyObjectState> | null = null;
private _stickyHeaderRef: StickyHeader<StickyObjectProps> | null = null;
private _stickyFooterRef: StickyFooter<StickyObjectProps> | null = null;
private _visibleIndicesAll: number[] = [];

constructor(props: P, context?: any) {
Expand All @@ -52,11 +53,11 @@ export default class StickyContainer<P extends StickyContainerProps> extends Rea
this._distanceFromWindow = childProps.distanceFromWindow ? childProps.distanceFromWindow : 0;
}

public componentWillReceiveProps(newProps: P): void {
public componentWillReceivePropsCompat(newProps: P): void {
this._initParams(newProps);
}

public render(): JSX.Element {
public renderCompat(): JSX.Element {
this._assertChildType();
const recycler: ReactElement<RecyclerListViewProps> = React.cloneElement(this.props.children, {
...this.props.children.props,
Expand All @@ -65,33 +66,33 @@ export default class StickyContainer<P extends StickyContainerProps> extends Rea
onScroll: this._onScroll,
});
return (
<View style={this.props.style ? this.props.style : {flex: 1}}>
<View style={this.props.style ? this.props.style : { flex: 1 }}>
{recycler}
{this.props.stickyHeaderIndices ? (
<StickyHeader ref={(stickyHeaderRef: any) => this._getStickyHeaderRef(stickyHeaderRef)}
stickyIndices={this.props.stickyHeaderIndices}
getLayoutForIndex={this._getLayoutForIndex}
getDataForIndex={this._getDataForIndex}
getLayoutTypeForIndex={this._getLayoutTypeForIndex}
getExtendedState={this._getExtendedState}
getRLVRenderedSize={this._getRLVRenderedSize}
getContentDimension={this._getContentDimension}
getRowRenderer={this._getRowRenderer}
getDistanceFromWindow={this._getDistanceFromWindow}
overrideRowRenderer={this.props.overrideRowRenderer}/>
stickyIndices={this.props.stickyHeaderIndices}
getLayoutForIndex={this._getLayoutForIndex}
getDataForIndex={this._getDataForIndex}
getLayoutTypeForIndex={this._getLayoutTypeForIndex}
getExtendedState={this._getExtendedState}
getRLVRenderedSize={this._getRLVRenderedSize}
getContentDimension={this._getContentDimension}
getRowRenderer={this._getRowRenderer}
getDistanceFromWindow={this._getDistanceFromWindow}
overrideRowRenderer={this.props.overrideRowRenderer} />
) : null}
{this.props.stickyFooterIndices ? (
<StickyFooter ref={(stickyFooterRef: any) => this._getStickyFooterRef(stickyFooterRef)}
stickyIndices={this.props.stickyFooterIndices}
getLayoutForIndex={this._getLayoutForIndex}
getDataForIndex={this._getDataForIndex}
getLayoutTypeForIndex={this._getLayoutTypeForIndex}
getExtendedState={this._getExtendedState}
getRLVRenderedSize={this._getRLVRenderedSize}
getContentDimension={this._getContentDimension}
getRowRenderer={this._getRowRenderer}
getDistanceFromWindow={this._getDistanceFromWindow}
overrideRowRenderer={this.props.overrideRowRenderer}/>
stickyIndices={this.props.stickyFooterIndices}
getLayoutForIndex={this._getLayoutForIndex}
getDataForIndex={this._getDataForIndex}
getLayoutTypeForIndex={this._getLayoutTypeForIndex}
getExtendedState={this._getExtendedState}
getRLVRenderedSize={this._getRLVRenderedSize}
getContentDimension={this._getContentDimension}
getRowRenderer={this._getRowRenderer}
getDistanceFromWindow={this._getDistanceFromWindow}
overrideRowRenderer={this.props.overrideRowRenderer} />
) : null}
</View>
);
Expand All @@ -110,15 +111,15 @@ export default class StickyContainer<P extends StickyContainerProps> extends Rea

private _getStickyHeaderRef = (stickyHeaderRef: any) => {
if (this._stickyHeaderRef !== stickyHeaderRef) {
this._stickyHeaderRef = stickyHeaderRef as (StickyHeader<StickyObjectProps, StickyObjectState> | null);
this._stickyHeaderRef = stickyHeaderRef as (StickyHeader<StickyObjectProps> | null);
// TODO: Resetting state once ref is initialized. Can look for better solution.
this._callStickyObjectsOnVisibleIndicesChanged(this._visibleIndicesAll);
}
}

private _getStickyFooterRef = (stickyFooterRef: any) => {
if (this._stickyFooterRef !== stickyFooterRef) {
this._stickyFooterRef = stickyFooterRef as (StickyFooter<StickyObjectProps, StickyObjectState> | null);
this._stickyFooterRef = stickyFooterRef as (StickyFooter<StickyObjectProps> | null);
// TODO: Resetting state once ref is initialized. Can look for better solution.
this._callStickyObjectsOnVisibleIndicesChanged(this._visibleIndicesAll);
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/sticky/StickyFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* Created by ananya.chandra on 20/09/18.
*/

import StickyObject, {StickyObjectProps, StickyObjectState, StickyType} from "./StickyObject";
import StickyObject, {StickyObjectProps, StickyType} from "./StickyObject";
import BinarySearch, {ValueAndIndex} from "../../utils/BinarySearch";

export default class StickyFooter<P extends StickyObjectProps, S extends StickyObjectState> extends StickyObject<P, S> {
export default class StickyFooter<P extends StickyObjectProps> extends StickyObject<P> {
constructor(props: P, context?: any) {
super(props, context);
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/sticky/StickyHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* Created by ananya.chandra on 20/09/18.
*/

import StickyObject, {StickyObjectProps, StickyObjectState, StickyType} from "./StickyObject";
import StickyObject, {StickyObjectProps, StickyType} from "./StickyObject";
import BinarySearch, {ValueAndIndex} from "../../utils/BinarySearch";

export default class StickyHeader<P extends StickyObjectProps, S extends StickyObjectState> extends StickyObject<P, S> {
export default class StickyHeader<P extends StickyObjectProps> extends StickyObject<P> {
constructor(props: P, context?: any) {
super(props, context);
}
Expand Down
26 changes: 11 additions & 15 deletions src/core/sticky/StickyObject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {Layout} from "../layoutmanager/LayoutManager";
import {Dimension} from "../dependencies/LayoutProvider";
import RecyclerListViewExceptions from "../exceptions/RecyclerListViewExceptions";
import CustomError from "../exceptions/CustomError";
import { ComponentCompat } from "../../utils/ComponentCompat";

export enum StickyType {
HEADER,
Expand All @@ -25,10 +26,7 @@ export interface StickyObjectProps {
getDistanceFromWindow: () => number;
overrideRowRenderer?: (type: string | number | undefined, data: any, index: number, extendedState?: object) => JSX.Element | JSX.Element[] | null;
}
export interface StickyObjectState {
visible: boolean;
}
export default abstract class StickyObject<P extends StickyObjectProps, S extends StickyObjectState> extends React.Component<P, S> {
export default abstract class StickyObject<P extends StickyObjectProps> extends ComponentCompat<P> {
protected stickyType: StickyType = StickyType.HEADER;
protected stickyTypeMultiplier: number = 1;
protected stickyVisiblity: boolean = false;
Expand Down Expand Up @@ -63,26 +61,23 @@ export default abstract class StickyObject<P extends StickyObjectProps, S extend

constructor(props: P, context?: any) {
super(props, context);
this.state = {
visible: this.stickyVisiblity,
} as S;
}

public componentWillReceiveProps(newProps: StickyObjectProps): void {
public componentWillReceivePropsCompat(newProps: StickyObjectProps): void {
this._initParams();
this.calculateVisibleStickyIndex(newProps.stickyIndices, this._smallestVisibleIndex, this._largestVisibleIndex,
this._offsetY, newProps.getDistanceFromWindow(), this._windowBound);
this._computeLayouts(newProps.stickyIndices);
this.stickyViewVisible(this.stickyVisiblity);
this.stickyViewVisible(this.stickyVisiblity, false);
}

public render(): JSX.Element | null {
public renderCompat(): JSX.Element | null {
return (
<Animated.View style={[
{position: "absolute", width: this._scrollableWidth, transform: [{translateY: this._stickyViewOffset}]},
this.containerPosition,
]}>
{this.state.visible ?
{this.stickyVisiblity ?
this._renderSticky()
: null}
</Animated.View>
Expand Down Expand Up @@ -154,10 +149,11 @@ export default abstract class StickyObject<P extends StickyObjectProps, S extend
protected abstract getCurrentYd(currentY: number, currentHeight: number): number;
protected abstract getScrollY(offsetY: number, scrollableHeight?: number): number | undefined;

protected stickyViewVisible(_visible: boolean): void {
this.setState({
visible: _visible,
});
protected stickyViewVisible(_visible: boolean, shouldTriggerRender: boolean = true): void {
this.stickyVisiblity = _visible;
if (shouldTriggerRender) {
this.setState({});
}
}

protected boundaryProcessing(offsetY: number, distanceFromWindow: number, windowBound?: number): void {
Expand Down
5 changes: 3 additions & 2 deletions src/core/viewrenderer/BaseViewRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from "react";
import { Dimension, BaseLayoutProvider } from "../dependencies/LayoutProvider";
import ItemAnimator from "../ItemAnimator";
import { LayoutManager } from "../layoutmanager/LayoutManager";
import { ComponentCompat } from "../../utils/ComponentCompat";

/***
* View renderer is responsible for creating a container of size provided by LayoutProvider and render content inside it.
Expand All @@ -28,7 +29,7 @@ export interface ViewRendererProps<T> {
internalSnapshot?: object;
layoutProvider?: BaseLayoutProvider;
}
export default abstract class BaseViewRenderer<T> extends React.Component<ViewRendererProps<T>, {}> {
export default abstract class BaseViewRenderer<T> extends ComponentCompat<ViewRendererProps<T>, {}> {
protected animatorStyleOverrides: object | undefined;

public shouldComponentUpdate(newProps: ViewRendererProps<any>): boolean {
Expand All @@ -53,7 +54,7 @@ export default abstract class BaseViewRenderer<T> extends React.Component<ViewRe
this.animatorStyleOverrides = undefined;
this.props.itemAnimator.animateDidMount(this.props.x, this.props.y, this.getRef() as object, this.props.index);
}
public componentWillMount(): void {
public componentWillMountCompat(): void {
this.animatorStyleOverrides = this.props.itemAnimator.animateWillMount(this.props.x, this.props.y, this.props.index);
}
public componentWillUnmount(): void {
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { AutoScroll } from "./utils/AutoScroll";
import { Layout, LayoutManager, Point, WrapGridLayoutManager } from "./core/layoutmanager/LayoutManager";
import ProgressiveListView from "./core/ProgressiveListView";
import { DebugHandlers } from "./core/devutils/debughandlers/DebugHandlers";
import { ComponentCompat } from "./utils/ComponentCompat";

export {
ContextProvider,
Expand All @@ -27,4 +28,5 @@ export {
OnRecreateParams,
DebugHandlers,
BaseDataProvider,
ComponentCompat,
};
2 changes: 1 addition & 1 deletion src/platform/reactnative/viewrenderer/ViewRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import BaseViewRenderer, { ViewRendererProps } from "../../../core/viewrenderer/
export default class ViewRenderer extends BaseViewRenderer<any> {
private _dim: Dimension = { width: 0, height: 0 };
private _viewRef: React.Component<ViewProperties, React.ComponentState> | null = null;
public render(): JSX.Element {
public renderCompat(): JSX.Element {
return this.props.forceNonDeterministicRendering ? (
<View ref={this._setRef}
onLayout={this._onLayout}
Expand Down
2 changes: 1 addition & 1 deletion src/platform/web/viewrenderer/ViewRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default class ViewRenderer extends BaseViewRenderer<any> {
this._checkSizeChange();
}

public render(): JSX.Element {
public renderCompat(): JSX.Element {
const style: CSSProperties = this.props.forceNonDeterministicRendering
? {
transform: this._getTransform(),
Expand Down
43 changes: 43 additions & 0 deletions src/utils/ComponentCompat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from "react";

//Interim solve given we want to be active on old react as well for now.
export abstract class ComponentCompat<T1 = {}, T2 = {}, SS = any> extends React.Component<T1, T2, SS> {
private _hasRenderedOnce: boolean = false;
private _didPropsChange: boolean = false;

constructor(props: T1, context?: any) {
super(props, context);
}

public shouldComponentUpdate(newProps: T1, newState: T2): boolean {
if (this.props !== newProps) {
this.componentWillReceivePropsCompat(newProps);
}
return true;
}

//setState inside will not update the existing cycle, not a true replacement for componentWillReceiveProps
public componentWillReceivePropsCompat(newProps: T1): void {
//no op
}

public componentWillMountCompat(): void {
//no op
}

public componentWillUpdateCompat(): void {
//no op
}

public render(): React.ReactNode {
if (!this._hasRenderedOnce) {
this._hasRenderedOnce = true;
this.componentWillMountCompat();
} else {
this.componentWillUpdateCompat();
}
return this.renderCompat();
}

public abstract renderCompat(): React.ReactNode;
}