Last active
February 4, 2021 13:17
-
-
Save js2me/16bb62768fffd70c3d63b2e0a69eb872 to your computer and use it in GitHub Desktop.
Effector utils for own usage
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 { Effect, Event, Store, createEvent, combine } from "effector"; | |
import { status } from "patronum"; | |
import { EffectState } from "patronum/status"; | |
export interface FetchingState { | |
loading: boolean; | |
done: boolean; | |
fail: boolean; | |
} | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
const isStore = <S = any>(value: unknown): value is Store<S> => { | |
return typeof value === "object" && value !== null && "getState" in value; | |
}; | |
const fetchingStateToStatus = (store: Store<FetchingState>): Store<EffectState> => { | |
return store.map((state) => | |
state.loading ? "pending" : state.fail ? "fail" : state.done ? "done" : "initial", | |
); | |
}; | |
export const fetching = ( | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
...effects: (Store<FetchingState> | Effect<any, any, any>)[] | |
): Store<FetchingState> => { | |
const $statuses = combine( | |
effects.map((effect) => | |
isStore<FetchingState>(effect) | |
? fetchingStateToStatus(effect) | |
: status({ effect, defaultValue: "initial" }), | |
), | |
(effectStates) => { | |
const loading = effectStates.some((state) => state === "pending"); | |
const done = !loading && effectStates.every((state) => state === "done"); | |
const fail = !loading && effectStates.some((state) => state === "fail"); | |
return { | |
loading, | |
done, | |
fail, | |
}; | |
}, | |
); | |
// $statuses.reset(globalReset); | |
return $statuses; | |
}; | |
export const once = <S extends unknown, P extends unknown, D extends unknown>({ | |
source, | |
condition, | |
payload, | |
target, | |
}: { | |
source: Store<S> | Event<S>; | |
condition?: (state: S) => boolean; | |
payload?: (state: S) => P; | |
target: Effect<P, D>; | |
}) => { | |
const subscription = source.watch((state: unknown) => { | |
if (!condition || condition(state as S)) { | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
target(payload ? payload(state as S) : (undefined as any)); | |
subscription(); | |
} | |
}); | |
}; | |
export const mergeEvents = <P extends unknown>(...events: Event<P>[]) => { | |
const event = createEvent<P>(); | |
event.watch((p: P) => { | |
events.forEach((e) => e(p)); | |
}); | |
return event; | |
}; | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
export const every = <S extends Store<any>>({ | |
predicate, | |
stores, | |
}: { | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
stores: S[]; | |
predicate: (state: S extends Store<infer State> ? State : never) => boolean; | |
}): Store<boolean> => { | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
return combine(stores).map((states) => !states.some((state) => !predicate(state as any))); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment