Skip to content

Instantly share code, notes, and snippets.

@den-churbanov
Created September 2, 2024 11:50
Show Gist options
  • Save den-churbanov/bd491d7666aea99dfb8b465069a4eae0 to your computer and use it in GitHub Desktop.
Save den-churbanov/bd491d7666aea99dfb8b465069a4eae0 to your computer and use it in GitHub Desktop.
import { createStore, Event, sample, Store } from 'effector';
import { once, readonly } from 'patronum';
interface TrackSliceOptions<T extends RouteParams, Route extends EffectorRoute<T> = EffectorRoute<T>> {
route: Route,
compare: (params: EffectorRouteParams<Route>) => boolean
}
interface SliceInstance<Params extends RouteParams> {
$opened: Store<boolean>,
opened: Event<Params>,
updated: Event<Params>,
openedOnce: Event<Params>,
closed: Event<Params>,
_reset: Event<void>
}
// create a "slice" of route based on params compare
export function trackRouteSlice<Route extends EffectorRoute<any>, Params = EffectorRouteParams<Route>>(
{
route,
compare
}: TrackSliceOptions<Params, Route>
) {
const $updates = createStore(false);
const $opened = createStore(false);
const opened: Event<Params> = sample({
clock: [route.opened, route.updated],
source: $updates,
filter: (updates, params) => compare(params) && !updates,
fn: (_, params) => params
});
const updated: Event<Params> = sample({
clock: [route.opened, route.updated],
source: $updates,
filter: (updates, params) => compare(params) && updates,
fn: (_, params) => params
});
const closed: Event<Params> = sample({
clock: [
route.closed,
sample({
clock: route.updated,
filter: params => !compare(params),
})
]
});
sample({
clock: opened,
fn: () => true,
target: $updates
});
$opened
.on(opened, () => true)
.on(closed, () => false);
$updates.reset(closed, route.closed);
const tab: SliceInstance<Params> = {
$opened: readonly($opened),
opened,
updated,
openedOnce: once({
source: opened,
reset: route.closed
}),
closed,
_reset: route.closed
}
return Object.freeze(tab);
}
// Track route parameter except undefined for current slice
// Example: on tabs change
export function trackSliceParameter<
Slice extends SliceInstance<any>,
Params = Slice extends SliceInstance<infer P> ? P : never,
ParamKey extends keyof Params = keyof Params,
>(
slice: Slice,
key: ParamKey
) {
const $param = createStore<Params[ParamKey]>(null);
sample({
clock: [
slice.opened,
slice.updated
],
filter: slice.$opened,
fn: params => params && params[key] ? params[key] : null,
target: $param
});
$param.reset(slice._reset);
return readonly($param);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment