Skip to content

Instantly share code, notes, and snippets.

@js2me
Last active February 4, 2021 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save js2me/16bb62768fffd70c3d63b2e0a69eb872 to your computer and use it in GitHub Desktop.
Save js2me/16bb62768fffd70c3d63b2e0a69eb872 to your computer and use it in GitHub Desktop.
Effector utils for own usage
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