Skip to content
This repository has been archived by the owner on Jan 14, 2022. It is now read-only.

Commit

Permalink
fix: Ошибки о неициализированных переменных
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitakoschelenko committed Jan 8, 2022
1 parent 6d1cf95 commit 00517a7
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 104 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
},
"peerDependencies": {
"@vkontakte/vk-bridge": "^2.4.8",
"@vkontakte/vkui": "^4.22.2",
"@vkontakte/vkui": "^4.23.0",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
Expand Down
156 changes: 91 additions & 65 deletions src/components.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import type { FC, DetailedReactHTMLElement, ReactElement } from 'react';

import React, {
Children,
cloneElement,
isValidElement,
useEffect,
useState
} from 'react';
import type { FC, ReactElement } from 'react';

import React, { Children, isValidElement, useEffect, useState } from 'react';
import {
Root as VKUIRoot,
Epic as VKUIEpic,
Expand All @@ -26,59 +20,54 @@ import { back } from './router';
import { initStructure } from './structure';
import { currentState, isBackCheck, swipebackHistory } from './history';
import { subscribe } from './listeners';
import { useParams } from './hooks';
import { useUpdate, useParams } from './hooks';

type StructureProps = {
autogen?: boolean;

type RouterProps = {
children: ReactElement;
};

/**
* Компонент-обёртка над приложением для работы обновления и стилей
* Компонент-обёртка над структурой для автоматической генерации
*/
export const Router: FC<RouterProps> = ({ children }) => {
export const Structure: FC<StructureProps> = ({ children, autogen = true }) => {
const [, setState] = useState(currentState);

useEffect(
() => subscribe((_, state) => setState(state ?? { ...currentState })),
[]
);
useEffect(() => {
if (autogen) initStructure(children);

subscribe((_, state) => setState(state ?? { ...currentState! }));
}, []);

return (
<>
<style>{`
.vkuiView__popout:empty, .vkuiPopoutRoot__popout:empty, .vkuiPopoutRoot--absolute:empty {
.vkuiView__popout:empty,
.vkuiPopoutRoot__popout:empty,
.vkuiPopoutRoot--absolute:empty {
display: none;
}
`}</style>

{Children.map(children, (child) =>
cloneElement(child as DetailedReactHTMLElement<any, HTMLElement>, null)
)}
{children}
</>
);
};

type StructureProps = {
children: ReactElement;
};

/**
* Компонент-обёртка над структурой для автоматической генерации
*/
export const Structure: FC<StructureProps> = ({ children }) => {
useEffect(() => initStructure(children), []);

return children;
};

/**
* Компонент-обёртка над ModalRoot из VKUI
*/
export const ModalRoot: FC<Omit<ModalRootProps, 'activeModal' | 'onClose'>> = (
props
) => {
const update = useUpdate();
const { modal = null } = useParams();

useEffect(() => {
subscribe(update);
}, []);

return (
<VKUIModalRoot activeModal={modal} onClose={back} {...props}>
{props.children}
Expand All @@ -90,8 +79,13 @@ export const ModalRoot: FC<Omit<ModalRootProps, 'activeModal' | 'onClose'>> = (
* Компонент-обёртка для работы попаутов
*/
export const PopoutRoot: FC = (props) => {
const update = useUpdate();
const { popout = null } = useParams();

useEffect(() => {
subscribe(update);
}, []);

const activePopout: ReactElement | undefined = popout
? (Children.toArray(props.children).find(
(child) =>
Expand All @@ -106,36 +100,60 @@ export const PopoutRoot: FC = (props) => {
/**
* Компонент-обёртка над Root из VKUI
*/
export const Root: FC<Omit<RootProps, 'activeView'>> = (props) => (
<VKUIRoot activeView={currentState?.view} {...props}>
{props.children}
</VKUIRoot>
);
export const Root: FC<Omit<RootProps, 'activeView'>> = (props) => {
const update = useUpdate();

useEffect(() => {
subscribe(update);
}, []);

return (
<VKUIRoot activeView={currentState?.view ?? '/'} {...props}>
{props.children}
</VKUIRoot>
);
};

/**
* Компонент-обёртка над Epic из VKUI
*/
export const Epic: FC<Omit<EpicProps, 'activeStory'>> = (props) => (
<VKUIEpic activeStory={currentState?.view} {...props}>
{props.children}
</VKUIEpic>
);
export const Epic: FC<Omit<EpicProps, 'activeStory'>> = (props) => {
const update = useUpdate();

useEffect(() => {
subscribe(update);
}, []);

return (
<VKUIEpic activeStory={currentState?.view ?? '/'} {...props}>
{props.children}
</VKUIEpic>
);
};

/**
* Компонент-обёртка над View из VKUI
*/
export const View: FC<
Omit<ViewProps, 'activePanel' | 'history' | 'onSwipeBack'>
> = (props) => (
<VKUIView
activePanel={currentState?.panel}
history={swipebackHistory}
onSwipeBack={back}
{...props}
>
{props.children}
</VKUIView>
);
> = (props) => {
const update = useUpdate();

useEffect(() => {
subscribe(update);
}, []);

return (
<VKUIView
activePanel={currentState?.panel ?? '/'}
history={swipebackHistory ?? []}
onSwipeBack={back}
{...props}
>
{props.children}
</VKUIView>
);
};

/**
* Компонент-обёртка над ViewInfinite из VKUI. Нестабильный, как и оригинальный компонент
Expand All @@ -145,14 +163,22 @@ export const ViewInfinite: FC<
ViewInfiniteProps,
'activePanel' | 'history' | 'onSwipeBack' | 'onBackCheck'
>
> = (props) => (
<VKUIViewInfinite
activePanel={currentState?.panel}
history={swipebackHistory}
onSwipeBack={back}
isBackCheck={isBackCheck}
{...props}
>
{props.children}
</VKUIViewInfinite>
);
> = (props) => {
const update = useUpdate();

useEffect(() => {
subscribe(update);
}, []);

return (
<VKUIViewInfinite
activePanel={currentState?.panel ?? '/'}
history={swipebackHistory ?? []}
onSwipeBack={back}
isBackCheck={isBackCheck}
{...props}
>
{props.children}
</VKUIViewInfinite>
);
};
14 changes: 7 additions & 7 deletions src/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { currentOptions } from './router';
import { currentStructure } from './structure';
import { getRandomId } from './utils';

export let currentState: State;
export let currentHistory: State[];
export let currentList: State[];
export let swipebackHistory: string[];
export let currentState: State | null = null;
export let currentHistory: State[] | null = null;
export let currentList: State[] | null = null;
export let swipebackHistory: string[] | null = null;

export let isBack: boolean = false;
export let internalPopstate: boolean = false;
Expand All @@ -17,8 +17,8 @@ export let shouldSkipPopstate: boolean = false;
*/
export function initHistory(): void {
currentState = currentStructure
? (parseRoute(currentOptions.defaultRoute) as State)
: createState(currentOptions.defaultRoute);
? (parseRoute(currentOptions?.defaultRoute ?? '/') as State)
: createState(currentOptions?.defaultRoute ?? '/');
currentHistory = [currentState];
currentList = [currentState];
swipebackHistory = [currentState.panel];
Expand Down Expand Up @@ -53,7 +53,7 @@ export function getHistoryURL(path: string): string {
[Mode.PATH]: path
};

return urls[currentOptions.mode];
return urls[currentOptions?.mode ?? Mode.NONE];
}

/**
Expand Down
17 changes: 12 additions & 5 deletions src/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import { useMemo } from 'react';
import { DispatchWithoutAction, useMemo, useReducer } from 'react';
import { parse } from 'querystring';

import { Meta, Params, State, Mode } from './types';
import { currentHistory, currentState, currentList } from './history';
import { currentOptions } from './router';

/**
* Хук для обновления компонента
*/
export const useUpdate = (): DispatchWithoutAction => {
return useReducer((x: number) => x + 1, 0)[1];
};

/**
* Хук для использования текущего состояния роутера
*/
export const useCurrentState = (): State => {
return currentState ?? {};
return currentState ?? ({} as State);
};

/**
Expand All @@ -26,7 +33,7 @@ export const useParams = <T extends Params>(): T => {
const params: Params = useMemo(() => {
if (
process.env.NODE_ENV === 'development' &&
currentOptions.mode === Mode.NONE
currentOptions?.mode === Mode.NONE
)
console.warn(
'Параметры не могут быть получены, так как роутер работает в режиме без хранения страницы и параметров в адресной строке. Смените mode на path или hash, чтобы исправить.'
Expand All @@ -37,7 +44,7 @@ export const useParams = <T extends Params>(): T => {
[Mode.NONE]: '',
[Mode.PATH]: location.search.slice(1),
[Mode.HASH]: location.hash.split('?')[1]
}[currentOptions.mode]
}[currentOptions?.mode ?? Mode.NONE]
) as Params;
}, [currentState?.path]);

Expand All @@ -49,7 +56,7 @@ export const useParams = <T extends Params>(): T => {
*/
export const useMeta = <T extends Meta>(id?: number | null): T => {
const found: State | undefined = useMemo(
() => currentList.find((currentState) => currentState?.id === id),
() => currentList?.find((currentState) => currentState?.id === id),
[currentState?.path]
);

Expand Down
Loading

0 comments on commit 00517a7

Please sign in to comment.