Skip to content

Instantly share code, notes, and snippets.

@js2me
Created June 18, 2021 22:41
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/f0cbaa958c2ec608f18e897c8fa4a91b to your computer and use it in GitHub Desktop.
Save js2me/f0cbaa958c2ec608f18e897c8fa4a91b to your computer and use it in GitHub Desktop.
Effector status of effects
import {
Effect,
Store,
combine,
guard,
createEvent,
restore,
sample,
} from "effector";
import { status as patronumStatus } from "patronum";
import { EffectState } from "patronum/status";
export interface EffectsStatus {
loading: boolean;
done: boolean;
fail: boolean;
}
const isStore = <S = unknown>(value: unknown): value is Store<S> => {
return typeof value === "object" && value !== null && "getState" in value;
};
const fetchingStateToStatus = (
store: Store<EffectsStatus>,
): Store<EffectState> => {
return store.map((state) =>
state.loading
? "pending"
: state.fail
? "fail"
: state.done
? "done"
: "initial",
);
};
/** status of effects */
export const status = ({
effects,
holdUpdate,
}: {
holdUpdate?: Store<boolean>;
effects: (Store<EffectsStatus> | Effect<_, _, _>)[];
}): Store<EffectsStatus> => {
const setAbleUpdate = createEvent<boolean>();
const $ableUpdate = restore(setAbleUpdate, true);
if (holdUpdate) {
guard({
source: holdUpdate,
filter: Boolean,
target: setAbleUpdate.prepend(() => false),
});
}
const $status = combine(
effects.map((effect) =>
isStore<EffectsStatus>(effect)
? fetchingStateToStatus(effect)
: patronumStatus({
effect: effect as Effect<unknown, unknown, unknown>,
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,
};
},
);
if (holdUpdate) {
guard({
source: sample({
clock: $status,
fn: ({ loading, done, fail }) =>
!loading && (done || fail) ? false : null,
}),
filter: (source): source is false => source !== null,
target: [holdUpdate, setAbleUpdate.prepend(() => true)],
});
}
return restore(
guard({
source: sample({
source: $ableUpdate,
clock: $status,
fn: (ableUpdate, status) => (ableUpdate ? status : null),
}),
filter: Boolean,
}),
$status.getState(),
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment