diff --git a/src/lib/teact/teactn.tsx b/src/lib/teact/teactn.tsx index 04efd8f0f..0fabdb9b1 100644 --- a/src/lib/teact/teactn.tsx +++ b/src/lib/teact/teactn.tsx @@ -14,6 +14,17 @@ import useUniqueId from '../../hooks/useUniqueId'; export default React; +interface Container { + mapStateToProps: MapStateToProps; + activationFn?: ActivationFn; + stuckTo?: any; + ownProps: Props; + mappedProps?: Props; + forceUpdate: Function; + DEBUG_updates: number; + DEBUG_componentName: string; +} + type GlobalState = AnyLiteral & { DEBUG_capturedId?: number }; @@ -36,7 +47,10 @@ type ActionHandler = ( ) => GlobalState | void | Promise; type MapStateToProps = (global: GlobalState, ownProps: OwnProps) => AnyLiteral; -type ActivationFn = (global: GlobalState, ownProps: OwnProps) => boolean; +type StickToFirstFn = (value: any) => boolean; +type ActivationFn = ( + global: GlobalState, ownProps: OwnProps, stickToFirst: StickToFirstFn, +) => boolean; let currentGlobal = {} as GlobalState; @@ -50,15 +64,7 @@ const DEBUG_releaseCapturedIdThrottled = throttleWithTickEnd(() => { const actionHandlers: Record = {}; const callbacks: Function[] = [updateContainers]; const actions = {} as Actions; -const containers = new Map; - activationFn?: ActivationFn; - ownProps: Props; - mappedProps?: Props; - forceUpdate: Function; - DEBUG_updates: number; - DEBUG_componentName: string; -}>(); +const containers = new Map(); const runCallbacksThrottled = throttleWithTickEnd(runCallbacks); @@ -161,10 +167,10 @@ function updateContainers() { // eslint-disable-next-line no-restricted-syntax for (const container of containers.values()) { const { - mapStateToProps, activationFn, ownProps, mappedProps, forceUpdate, + mapStateToProps, ownProps, mappedProps, forceUpdate, } = container; - if (activationFn && !activationFn(currentGlobal, ownProps)) { + if (!activateContainer(container, currentGlobal, ownProps)) { continue; } @@ -266,8 +272,7 @@ export function withGlobal( } if (!container.mappedProps || ( - !arePropsShallowEqual(container.ownProps, props) - && (!activationFn || activationFn(currentGlobal, props)) + !arePropsShallowEqual(container.ownProps, props) && activateContainer(container, currentGlobal, props) )) { try { container.mappedProps = mapStateToProps(currentGlobal, props); @@ -288,6 +293,21 @@ export function withGlobal( }; } +function activateContainer(container: Container, global: GlobalState, props: Props) { + const { activationFn, stuckTo } = container; + if (!activationFn) { + return true; + } + + return activationFn(global, props, (stickTo: any) => { + if (stickTo && !stuckTo) { + container.stuckTo = stickTo; + } + + return stickTo && (!stuckTo || stuckTo === stickTo); + }); +} + export function typify< ProjectGlobalState, ActionPayloads, @@ -322,7 +342,7 @@ export function typify< ) => void, withGlobal: withGlobal as ( mapStateToProps: (global: ProjectGlobalState, ownProps: OwnProps) => AnyLiteral, - activationFn?: (global: ProjectGlobalState, ownProps: OwnProps) => boolean, + activationFn?: (global: ProjectGlobalState, ownProps: OwnProps, stickToFirst: StickToFirstFn) => boolean, ) => (Component: FC) => FC, }; }