Skip to content

Commit

Permalink
MA-19001: fix run-sync
Browse files Browse the repository at this point in the history
  • Loading branch information
pavel-nikitin-2022 committed Aug 7, 2024
1 parent cb14765 commit 6f75fc0
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 44 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
v1.4.6
-
- Устранены проблемы, связанные с работой runSync, все переданные переходы, выполняются

v1.4.5
-
- Устранена проблема с синхронизацией состояния роутера при многократном вызове хуков
Expand Down
42 changes: 25 additions & 17 deletions src/components/RouterProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { Action, Router } from '@remix-run/router';
import { PopoutContext, RouteContext, RouterContext } from '../contexts';
import { ReactElement, ReactNode, useEffect, useLayoutEffect, useMemo, useState } from 'react';
import {
ReactElement,
ReactNode,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from 'react';
import { DefaultRouteNavigator } from '../services/DefaultRouteNavigator';
import bridge from '@vkontakte/vk-bridge';
import { DefaultNotFound } from './DefaultNotFound';
import { getRouteContext, useForceUpdate } from '../utils/utils';
import { getRouteContext } from '../utils/utils';
import { ViewHistory } from '../services/ViewHistory';
import { useBlockForwardToModals } from '../hooks/useBlockForwardToModals';
import { SEARCH_PARAM_INFLATE, STATE_KEY_SHOW_POPOUT, UNIVERSAL_URL } from '../const';
Expand Down Expand Up @@ -37,24 +45,21 @@ export function RouterProvider({
useBridge = true,
throttled = true,
}: RouterProviderProps): ReactElement {
const forceUpdate = useForceUpdate();
const [popout, setPopout] = useState<JSX.Element | null>(null);
const [viewHistory] = useState<ViewHistory>(new ViewHistory());
const [panelsHistory, setPanelsHistory] = useState<string[]>([]);
const [transactionExecutor, setTransactionExecutor] = useState<TransactionExecutor>(
new TransactionExecutor(forceUpdate),
);
const transactionExecutorRef = useRef(new TransactionExecutor());
const isPopoutShown = router.state.location.state?.[STATE_KEY_SHOW_POPOUT];

const dataRouterContext = useMemo(() => {
const routeNavigator: RouteNavigator = new DefaultRouteNavigator(
router,
viewHistory,
transactionExecutor,
transactionExecutorRef.current,
setPopout,
);
return { router, routeNavigator, viewHistory };
}, [router, viewHistory, transactionExecutor, setPopout]);
}, [router, viewHistory, setPopout]);

const routeContext = useMemo(
() => getRouteContext(router.state, panelsHistory),
Expand All @@ -77,7 +82,7 @@ export function RouterProvider({
router.subscribe((state) => {
viewHistory.updateNavigation(state);
setPanelsHistory(viewHistory.panelsHistory);
transactionExecutor.doNext();
transactionExecutorRef.current.doNext();
});

if (useBridge) {
Expand All @@ -95,22 +100,25 @@ export function RouterProvider({
});
}

const executor = new TransactionExecutor(forceUpdate);
setTransactionExecutor(executor);
const searchParams = createSearchParams(router.state.location.search);
const enableFilling = Boolean(searchParams.get(SEARCH_PARAM_INFLATE));
hierarchy &&
enableFilling &&
fillHistory(hierarchy, dataRouterContext.routeNavigator, routeContext, executor);
if (hierarchy && enableFilling) {
fillHistory(
hierarchy,
dataRouterContext.routeNavigator,
routeContext,
transactionExecutorRef.current,
);
}
}, [router]);

useLayoutEffect(() => {
ContextThrottleService.updateThrottledServiceSettings({
interval,
firstActionDelay: transactionExecutor.initialDelay,
enable: throttled || Boolean(transactionExecutor.initialDelay),
throttled,
transactionExecutor: transactionExecutorRef.current,
});
}, [transactionExecutor.initialDelay, interval, throttled]);
}, [interval, throttled]);

const routeNotFound = Boolean(
!routeContext.match ||
Expand Down
28 changes: 17 additions & 11 deletions src/services/ContextThrottleService.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { EventBus } from './EventBus';
import { TransactionExecutor } from './TransactionExecutor';

interface ContextThrottleInfo {
prevValue: unknown;
updateTimerId: number;
throttledValue: unknown;
lastUpdateTimestamp: number;
updateTimerId: number;
}

interface ContextThrottleServiceSettings {
interval: number;
firstActionDelay: number;
enable: boolean;
throttled: boolean;
transactionExecutor: TransactionExecutor;
}

export class ContextThrottleService {
private static instance?: ContextThrottleService;
private enable = true;
private interval = 0;
private firstActionDelay = 0;
private throttled = true;
private contextThrottleMap: Record<string, ContextThrottleInfo> = {};
private transactionExecutor?: TransactionExecutor;

// eslint-disable-next-line @typescript-eslint/no-empty-function
private constructor() {}
Expand Down Expand Up @@ -51,8 +52,7 @@ export class ContextThrottleService {
private getTimeUntilNextUpdate(lastUpdateTimestamp: number) {
const timeSinceLastUpdate = Date.now() - lastUpdateTimestamp;
const delayUntilNextUpdate = this.interval - timeSinceLastUpdate;
const initialDelay = delayUntilNextUpdate <= 0 ? this.firstActionDelay : 0;
return Math.max(initialDelay, delayUntilNextUpdate);
return delayUntilNextUpdate;
}

private updateContextValue<T>(contextName: string, newValue: T) {
Expand All @@ -65,27 +65,33 @@ export class ContextThrottleService {

private throttleUpdateContextValue<T>(contextName: string, newValue: T) {
const contextData = this.getContextThrottleInfoByName(contextName);
clearTimeout(contextData.updateTimerId);
if (this.isRunSyncActive()) return;

const lastUpdateTimestamp = contextData.lastUpdateTimestamp;
const timeUntilNextUpdate = this.getTimeUntilNextUpdate(lastUpdateTimestamp);

if (timeUntilNextUpdate <= 0) {
this.updateContextValue(contextName, newValue);
} else {
clearTimeout(contextData.updateTimerId);
contextData.updateTimerId = setTimeout(() => {
this.updateContextValue(contextName, newValue);
}, timeUntilNextUpdate);
}
}

private isRunSyncActive() {
return this.transactionExecutor?.isRunSyncActive;
}

public static triggerContextUpdate<T>(contextName: string, newValue: T) {
const throttledService = ContextThrottleService.getInstance();

if (!throttledService.isContextChange(contextName, newValue)) {
return;
}

if (!throttledService.enable) {
if (!throttledService.throttled && !throttledService.isRunSyncActive()) {
throttledService.updateContextValue(contextName, newValue);
} else {
throttledService.throttleUpdateContextValue(contextName, newValue);
Expand All @@ -94,8 +100,8 @@ export class ContextThrottleService {

public static updateThrottledServiceSettings(settings: ContextThrottleServiceSettings) {
const throttledService = ContextThrottleService.getInstance();
throttledService.enable = settings.enable;
throttledService.interval = settings.interval;
throttledService.firstActionDelay = settings.firstActionDelay;
throttledService.throttled = settings.throttled;
throttledService.transactionExecutor = settings.transactionExecutor;
}
}
12 changes: 5 additions & 7 deletions src/services/TransactionExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@ import { NavigationTransaction } from '../entities/NavigationTransaction';
export class TransactionExecutor {
private transactions: NavigationTransaction[] = [];

constructor(private forceUpdate: () => void) {}
get isRunSyncActive() {
const hasMultipleTransactions = this.transactions.length > 1;
const hasSingleMultiActionTransaction =
this.transactions.length === 1 && this.transactions[0].isMultiAction;

get initialDelay(): number {
return this.transactions.length > 1 ||
(this.transactions.length > 0 && this.transactions[0].isMultiAction)
? 100
: 0;
return hasMultipleTransactions || hasSingleMultiActionTransaction;
}

add(transaction: NavigationTransaction): void {
this.transactions.push(transaction);
this.forceUpdate();
}

async doNext(): Promise<void> {
Expand Down
9 changes: 0 additions & 9 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { AgnosticRouteMatch, Location, Params, RouterState } from '@remix-run/ro
import { RouteContextObject } from '../contexts';
import { PageInternal } from '../type';
import { STATE_KEY_SHOW_MODAL, STATE_KEY_SHOW_POPOUT } from '../const';
import { useState } from 'react';

export function getParamKeys(path: string | undefined): string[] {
return path?.match(/\/:[^\/]+/g)?.map((param) => param.replace('/', '')) ?? [];
Expand Down Expand Up @@ -54,14 +53,6 @@ export function getDisplayName(WrappedComponent: { displayName?: string; name?:
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}

export function useForceUpdate() {
const [, setState] = useState(0);

return () => {
setState(Date.now());
};
}

export function warning(cond: any, message: string) {
if (!cond) {
if (typeof console !== 'undefined') console.warn(message);
Expand Down

0 comments on commit 6f75fc0

Please sign in to comment.