Skip to content

Commit d228f73

Browse files
committed
feat: Upgraded createRouteView & createRoutesView
1 parent d14e750 commit d228f73

File tree

4 files changed

+75
-59
lines changed

4 files changed

+75
-59
lines changed

src/create-route-view.tsx

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,39 @@
11
import React from "react";
2-
import { combine } from "effector";
3-
import { useUnit } from "effector-react";
42
import { RouteInstance } from "atomic-router";
53

6-
export const createRouteView = <Props,>(
7-
route: RouteInstance<any> | RouteInstance<any>[],
8-
View: React.FC<Props>
9-
) => {
10-
const $isOpened = Array.isArray(route)
11-
? combine(combine(route.map((r) => r.$isOpened)), (isOpened) => isOpened.includes(true))
12-
: route.$isOpened;
4+
import { useIsOpened } from "./use-is-opened";
5+
6+
export type RouteViewConfig<Props, Params> = {
7+
route: RouteInstance<Params> | RouteInstance<Params>[];
8+
view: React.FC<Props>;
9+
otherwise?: React.FC<Props>;
10+
};
1311

14-
function RouteView(props: Props) {
15-
const isOpened = useUnit($isOpened);
12+
export const createRouteView = <
13+
Props,
14+
Params,
15+
Config extends {
16+
[key in keyof RouteViewConfig<Props, Params>]?: RouteViewConfig<Props, Params>[key];
17+
}
18+
>(
19+
config: Config
20+
) => {
21+
return (props: Props & Omit<RouteViewConfig<Props, Params>, keyof Config>) => {
22+
const mergedConfig = { ...config, ...props } as RouteViewConfig<Props, Params>;
23+
const isOpened = useIsOpened(mergedConfig.route);
1624

1725
if (isOpened) {
26+
const View = mergedConfig.view;
27+
1828
return <View {...props} />;
1929
}
2030

21-
return null;
22-
}
31+
if (mergedConfig.otherwise) {
32+
const Otherwise = mergedConfig.otherwise;
2333

24-
return RouteView;
34+
return <Otherwise {...props} />;
35+
}
36+
37+
return null;
38+
};
2539
};

src/create-routes-view.tsx

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,40 @@
1-
import { combine } from "effector";
2-
import { useUnit } from "effector-react";
31
import React, { FC } from "react";
42
import { RouteInstance } from "atomic-router";
5-
import { createRouteView } from "./create-route-view";
6-
7-
export const createRoutesView = (config: {
8-
routes: { route: RouteInstance<any> | RouteInstance<any>[]; view: FC<any> }[];
9-
notFound?: FC<any>;
10-
}) => {
11-
const views = config.routes.map(({ route, view }) => createRouteView(route, view));
12-
const $isSomeOpened = combine(
13-
...config.routes
14-
.map(({ route }) => route)
15-
.flat()
16-
.map((route) => route.$isOpened),
17-
// @ts-expect-error
18-
(...isOpened) => isOpened.some(Boolean)
19-
);
20-
21-
const NotFound = config.notFound;
22-
23-
return () => {
24-
const isSomeOpened = useUnit($isSomeOpened);
25-
26-
if (!isSomeOpened && NotFound) {
27-
return <NotFound />;
3+
4+
import { useIsOpened } from "./use-is-opened";
5+
6+
type RouteRecord<Props, Params> = {
7+
route: RouteInstance<Params> | RouteInstance<Params>[];
8+
view: FC<Props>;
9+
};
10+
11+
export type RoutesViewConfig = {
12+
routes: RouteRecord<unknown, unknown>[];
13+
otherwise?: React.FC<unknown>;
14+
};
15+
16+
export const createRoutesView = <Config extends RoutesViewConfig>(config: Config) => {
17+
return (props: Omit<Config, keyof Config>) => {
18+
const mergedConfig = { ...config, ...props };
19+
const routes = mergedConfig.routes.map((routeRecord) => {
20+
const isOpened = useIsOpened(routeRecord.route);
21+
return { ...routeRecord, isOpened };
22+
});
23+
24+
for (const route of routes) {
25+
if (route.isOpened) {
26+
const View = route.view;
27+
28+
return <View />;
29+
}
30+
}
31+
32+
if (mergedConfig.otherwise) {
33+
const Otherwise = mergedConfig.otherwise;
34+
35+
return <Otherwise />;
2836
}
29-
return (
30-
<>
31-
{views.map((View, idx) => (
32-
<View key={idx} />
33-
))}
34-
</>
35-
);
37+
38+
return null;
3639
};
3740
};

src/route.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,15 @@
11
import React, { FC } from 'react';
2-
import { useStoreMap } from 'effector-react';
32
import { RouteInstance, RouteParams } from 'atomic-router';
43

5-
import { useRouter } from './router-provider';
4+
import { useIsOpened } from './use-is-opened';
65

76
type Props<Params extends RouteParams> = {
87
route: RouteInstance<Params> | RouteInstance<Params>[];
98
view: FC;
109
};
1110

1211
export function Route<Params>({ route, view: Component }: Props<Params>) {
13-
const router = useRouter();
14-
/* eslint-disable */
15-
const isOpened = useStoreMap({
16-
store: router.$activeRoutes,
17-
keys: [route],
18-
fn: (activeRoutes, [route]) => {
19-
return Array.isArray(route)
20-
? route.some(route => activeRoutes.includes(route))
21-
: activeRoutes.includes(route);
22-
},
23-
});
12+
const isOpened = useIsOpened(route);
2413

2514
if (isOpened) {
2615
return <Component />;

src/use-is-opened.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useUnit } from 'effector-react';
2+
import { RouteInstance } from 'atomic-router';
3+
4+
export const useIsOpened = (
5+
route: RouteInstance<any> | RouteInstance<any>[]
6+
) => {
7+
return Array.isArray(route)
8+
? useUnit(route.map((route) => route.$isOpened)).some(Boolean)
9+
: useUnit(route.$isOpened);
10+
};

0 commit comments

Comments
 (0)