Created
September 2, 2024 11:50
-
-
Save den-churbanov/bd491d7666aea99dfb8b465069a4eae0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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