[Perf] Transition: Get rid of redundant slide wrappers
This commit is contained in:
parent
982ba8c3a7
commit
ecf4ffb7ae
@ -47,6 +47,7 @@ enum AppScreens {
|
||||
inactive,
|
||||
}
|
||||
|
||||
const TRANSITION_RENDER_COUNT = Object.keys(AppScreens).length / 2;
|
||||
const INACTIVE_PAGE_TITLE = `${PAGE_TITLE} ${INACTIVE_MARKER}`;
|
||||
|
||||
const App: FC<StateProps> = ({
|
||||
@ -204,7 +205,7 @@ const App: FC<StateProps> = ({
|
||||
}, [theme]);
|
||||
|
||||
return (
|
||||
<UiLoader key="Loader" page={page} isMobile={isMobile}>
|
||||
<UiLoader page={page} isMobile={isMobile}>
|
||||
<Transition
|
||||
name="fade"
|
||||
activeKey={activeKey}
|
||||
@ -213,6 +214,7 @@ const App: FC<StateProps> = ({
|
||||
'full-height',
|
||||
(activeKey === AppScreens.auth || prevActiveKey === AppScreens.auth) && 'is-auth',
|
||||
)}
|
||||
renderCount={TRANSITION_RENDER_COUNT}
|
||||
>
|
||||
{renderContent}
|
||||
</Transition>
|
||||
|
||||
@ -484,19 +484,19 @@ const LeftColumn: FC<StateProps> = ({
|
||||
activeKey={contentType}
|
||||
shouldCleanup
|
||||
cleanupExceptionKey={ContentType.Main}
|
||||
shouldWrap
|
||||
wrapExceptionKey={ContentType.Main}
|
||||
id="LeftColumn"
|
||||
>
|
||||
{(isActive) => (
|
||||
<>
|
||||
{renderContent(isActive)}
|
||||
<div
|
||||
className="resize-handle"
|
||||
onMouseDown={initResize}
|
||||
onMouseUp={handleMouseUp}
|
||||
onDoubleClick={resetResize}
|
||||
/>
|
||||
</>
|
||||
afterChildren={(
|
||||
<div
|
||||
className="resize-handle"
|
||||
onMouseDown={initResize}
|
||||
onMouseUp={handleMouseUp}
|
||||
onDoubleClick={resetResize}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
{renderContent}
|
||||
</Transition>
|
||||
);
|
||||
};
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
|
||||
> .Transition {
|
||||
flex: 1;
|
||||
|
||||
@ -172,6 +172,8 @@ const LeftMain: FC<OwnProps> = ({
|
||||
activeKey={content}
|
||||
shouldCleanup
|
||||
cleanupExceptionKey={LeftColumnContent.ChatList}
|
||||
shouldWrap
|
||||
wrapExceptionKey={LeftColumnContent.ChatList}
|
||||
>
|
||||
{(isActive) => {
|
||||
switch (content) {
|
||||
|
||||
@ -451,6 +451,7 @@ const Settings: FC<OwnProps> = ({
|
||||
name={shouldSkipTransition ? 'none' : LAYERS_ANIMATION_NAME}
|
||||
activeKey={currentScreen}
|
||||
renderCount={TRANSITION_RENDER_COUNT}
|
||||
shouldWrap
|
||||
>
|
||||
{renderCurrentSection}
|
||||
</Transition>
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React, {
|
||||
useEffect, memo, useCallback, useState, useRef,
|
||||
useEffect, memo, useCallback, useState, useRef, useLayoutEffect,
|
||||
} from '../../lib/teact/teact';
|
||||
import { addExtraClass } from '../../lib/teact/teact-dom';
|
||||
import { getActions, getGlobal, withGlobal } from '../../global';
|
||||
|
||||
import type { AnimationLevel, LangCode } from '../../types';
|
||||
@ -231,6 +232,9 @@ const Main: FC<OwnProps & StateProps> = ({
|
||||
void loadBundle(Bundles.Calls);
|
||||
}, CALL_BUNDLE_LOADING_DELAY_MS);
|
||||
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { isDesktop } = useAppLayout();
|
||||
useEffect(() => {
|
||||
if (!isLeftColumnOpen && !isMiddleColumnOpen && !isDesktop) {
|
||||
@ -348,6 +352,14 @@ const Main: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
}, [lastSyncTime, openChat]);
|
||||
|
||||
// Restore Transition slide class after async rendering
|
||||
useLayoutEffect(() => {
|
||||
const container = containerRef.current!;
|
||||
if (container.parentNode!.childElementCount === 1) {
|
||||
addExtraClass(container, 'Transition__slide--active');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const leftColumnTransition = useShowTransition(
|
||||
isLeftColumnOpen, undefined, true, undefined, shouldSkipHistoryAnimations, undefined, true,
|
||||
);
|
||||
@ -445,7 +457,7 @@ const Main: FC<OwnProps & StateProps> = ({
|
||||
usePreventPinchZoomGesture(isMediaViewerOpen);
|
||||
|
||||
return (
|
||||
<div id="Main" className={className}>
|
||||
<div ref={containerRef} id="Main" className={className}>
|
||||
<LeftColumn />
|
||||
<MiddleColumn isMobile={isMobile} />
|
||||
<RightColumn isMobile={isMobile} />
|
||||
|
||||
@ -454,7 +454,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
<InfiniteScroll
|
||||
ref={containerRef}
|
||||
className="Profile custom-scroll"
|
||||
itemSelector={buildInfiniteScrollItemSelector(resultType)}
|
||||
itemSelector={`.shared-media-transition > .Transition__slide--active.${resultType}-list > .scroll-item`}
|
||||
items={canRenderContent ? viewportIds : undefined}
|
||||
cacheBuster={cacheBuster}
|
||||
sensitiveArea={PROFILE_SENSITIVE_AREA}
|
||||
@ -515,15 +515,6 @@ function renderProfileInfo(chatId: string, resolvedUserId: string | undefined, i
|
||||
);
|
||||
}
|
||||
|
||||
function buildInfiniteScrollItemSelector(resultType: string) {
|
||||
return [
|
||||
// Used on first render
|
||||
`.shared-media-transition > div:only-child > .${resultType}-list > .scroll-item`,
|
||||
// Used after transition
|
||||
`.shared-media-transition > .Transition__slide--active > .${resultType}-list > .scroll-item`,
|
||||
].join(', ');
|
||||
}
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global, { chatId, topicId, isMobile }): StateProps => {
|
||||
const chat = selectChat(global, chatId);
|
||||
|
||||
@ -30,14 +30,14 @@ export default function useTransitionFixes(
|
||||
if (container.style.overflowY !== 'hidden') {
|
||||
const scrollBarWidth = container.offsetWidth - container.clientWidth;
|
||||
container.style.overflowY = 'hidden';
|
||||
container.style.marginRight = `${scrollBarWidth}px`;
|
||||
container.style.paddingRight = `${scrollBarWidth}px`;
|
||||
}
|
||||
}, [containerRef]);
|
||||
|
||||
const releaseTransitionFix = useCallback(() => {
|
||||
const container = containerRef.current!;
|
||||
container.style.overflowY = 'scroll';
|
||||
container.style.marginRight = '0';
|
||||
container.style.paddingRight = '0';
|
||||
}, [containerRef]);
|
||||
|
||||
return { applyTransitionFix, releaseTransitionFix };
|
||||
|
||||
@ -12,8 +12,10 @@
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.Transition__slide--active):not(.from):not(.to) {
|
||||
&:not(.slide-optimized):not(.slide-optimized-rtl) {
|
||||
> .Transition__slide:not(.Transition__slide--active):not(.from):not(.to) {
|
||||
display: none !important; // Best performance when animating container
|
||||
//transform: scale(0); // Shortest initial delay
|
||||
}
|
||||
@ -36,7 +38,6 @@
|
||||
|
||||
#root & > .Transition__slide {
|
||||
position: absolute;
|
||||
display: block !important;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transition: transform var(--slide-transition);
|
||||
@ -348,7 +349,7 @@
|
||||
|
||||
&.slide-layers {
|
||||
--background-color: var(--color-background);
|
||||
background: black;
|
||||
background: black !important;
|
||||
|
||||
> .Transition__slide {
|
||||
background: var(--background-color);
|
||||
@ -427,6 +428,7 @@
|
||||
&.push-slide.backwards {
|
||||
> .to {
|
||||
transform: scale(0.7);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&.animating {
|
||||
|
||||
@ -29,18 +29,23 @@ export type TransitionProps = {
|
||||
shouldRestoreHeight?: boolean;
|
||||
shouldCleanup?: boolean;
|
||||
cleanupExceptionKey?: number;
|
||||
// Used by async components which are usually remounted during first animation
|
||||
shouldWrap?: boolean;
|
||||
wrapExceptionKey?: number;
|
||||
isDisabled?: boolean;
|
||||
id?: string;
|
||||
className?: string;
|
||||
onStart?: NoneToVoidFunction;
|
||||
onStop?: NoneToVoidFunction;
|
||||
children: React.ReactNode | ChildrenFn;
|
||||
afterChildren?: React.ReactNode;
|
||||
};
|
||||
|
||||
const FALLBACK_ANIMATION_END = 1000;
|
||||
const CLASSES = {
|
||||
slide: 'Transition__slide',
|
||||
active: 'Transition__slide--active',
|
||||
afterSlides: 'Transition__after-slides',
|
||||
};
|
||||
|
||||
const Transition: FC<TransitionProps> = ({
|
||||
@ -52,11 +57,14 @@ const Transition: FC<TransitionProps> = ({
|
||||
shouldRestoreHeight,
|
||||
shouldCleanup,
|
||||
cleanupExceptionKey,
|
||||
shouldWrap,
|
||||
wrapExceptionKey,
|
||||
id,
|
||||
className,
|
||||
onStart,
|
||||
onStop,
|
||||
children,
|
||||
afterChildren,
|
||||
}) => {
|
||||
// No need for a container to update on change
|
||||
const { animationLevel } = getGlobal().settings.byKey;
|
||||
@ -94,7 +102,8 @@ const Transition: FC<TransitionProps> = ({
|
||||
}
|
||||
|
||||
const container = containerRef.current!;
|
||||
const childElements = Array.from(container.children) as HTMLElement[];
|
||||
const childElements = (Array.from(container.children) as HTMLElement[])
|
||||
.filter((el) => !el.classList.contains(CLASSES.afterSlides));
|
||||
|
||||
childElements.forEach((el) => {
|
||||
addExtraClass(el, CLASSES.slide);
|
||||
@ -113,7 +122,9 @@ const Transition: FC<TransitionProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const childNodes = Array.from(container.childNodes);
|
||||
const childNodes = Array.from(container.childNodes)
|
||||
.filter((el) => !(el instanceof HTMLElement && el.classList.contains(CLASSES.afterSlides)));
|
||||
|
||||
if (!activeKeyChanged || !childNodes.length) {
|
||||
return;
|
||||
}
|
||||
@ -271,16 +282,21 @@ const Transition: FC<TransitionProps> = ({
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={key} teactOrderKey={key}>{
|
||||
typeof render === 'function'
|
||||
? render(key === activeKey, key === prevActiveKey, activeKey)
|
||||
: render
|
||||
}
|
||||
</div>
|
||||
);
|
||||
const rendered = typeof render === 'function'
|
||||
? render(key === activeKey, key === prevActiveKey, activeKey)
|
||||
: render;
|
||||
|
||||
return (shouldWrap && key !== wrapExceptionKey) || asFastList
|
||||
? <div key={key} teactOrderKey={key}>{rendered}</div>
|
||||
: rendered;
|
||||
});
|
||||
|
||||
if (afterChildren) {
|
||||
contents.push((
|
||||
<div className={CLASSES.afterSlides}>{afterChildren}</div>
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user