import { split } from "effector";
Choose one of cases by given conditions. It βsplitsβ source unit into several events, which fires when payload matches their conditions. Works like pattern matching for payload values and external stores
Concepts
Case mode
Mode in which target case is selected by the name of its field. Case could be selected from data in source
by case function or from external case store which kept current case name. After selection data from source
will be sent to corresponding cases[fieldName]
(if there is one), if none of the fields matches, then the data will be sent to cases.__
(if there is one).
See also:
Matching mode
Mode in which each case is sequentially matched by stores and functions in fields of match
object.
If one of the fields got true
from store value or return of function, then the data from source
will be sent to corresponding cases[fieldName]
(if there is one), if none of the fields matches, then the data will be sent to cases.__
(if there is one)
See also:
Case store
Store with a string which will be used to choose the case by its name. Placed directly in match
field.
split({
source: Unit<T>
// case store
match: Store<'first' | 'second'>,
cases: {
first: Unit<T> | Unit<T>[],
second: Unit<T> | Unit<T>[],
__?: Unit<T> | Unit<T>[]
}
})
Case function
String-returning function which will be called with value from source
to choose the case by its name. Placed directly in match
field, should be pure
split({
source: Unit<T>
// case function
match: (value: T) => 'first' | 'second',
cases: {
first: Unit<T> | Unit<T>[],
second: Unit<T> | Unit<T>[],
__?: Unit<T> | Unit<T>[]
}
})
Matcher store
Boolean store which indicates whether to choose the particular case or try the next one. Placed in fields of match
object, might be mixed with matcher functions
split({
source: Unit<T>
match: {
// matcher store
first: Store<boolean>,
second: Store<boolean>
},
cases: {
first: Unit<T> | Unit<T>[],
second: Unit<T> | Unit<T>[],
__?: Unit<T> | Unit<T>[]
}
})
Matcher function
Case store, case function and matcher store are supported since effector 21.8.0
Boolean-returning function which indicates whether to choose the particular case or try the next one. Placed in fields of match
object, might be mixed with matcher stores, should be pure
split({
source: Unit<T>
match: {
// matcher function
first: (value: T) => boolean,
second: (value: T) => boolean
},
cases: {
first: Unit<T> | Unit<T>[],
second: Unit<T> | Unit<T>[],
__?: Unit<T> | Unit<T>[]
}
})
Methods
split({ source, match, cases })
Formulae
split({ source, match, cases });
split({
source: Unit<T>
// case function
match: (data: T) => 'a' | 'b',
cases: {
a: Unit<T> | Unit<T>[],
b: Unit<T> | Unit<T>[],
__?: Unit<T> | Unit<T>[]
}
})
split({
source: Unit<T>
// case store
match: Store<'a' | 'b'>,
cases: {
a: Unit<T> | Unit<T>[],
b: Unit<T> | Unit<T>[],
__?: Unit<T> | Unit<T>[]
}
})
split({
source: Unit<T>
match: {
// matcher function
a: (data: T) => boolean,
// matcher store
b: Store<boolean>
},
cases: {
a: Unit<T> | Unit<T>[],
b: Unit<T> | Unit<T>[],
__?: Unit<T> | Unit<T>[]
}
})
Arguments
source
: Unit which will trigger computation insplit
match
: Single store with string, single function which returns string or object with boolean stores and functions which returns booleancases
: Object with units or arrays of units to which data will be passed fromsource
after case selection
Returns
void
Examples
Basic
import { split, createEffect, createEvent } from "effector";
const messageReceived = createEvent();
const showTextPopup = createEvent();
const playAudio = createEvent();
const reportUnknownMessageTypeFx = createEffect(({ type }) => {
console.log("unknown message:", type);
});
split({
source: messageReceived,
match: {
text: (msg) => msg.type === "text",
audio: (msg) => msg.type === "audio",
},
cases: {
text: showTextPopup,
audio: playAudio,
__: reportUnknownMessageTypeFx,
},
});
showTextPopup.watch(({ value }) => {
console.log("new message:", value);
});
messageReceived({
type: "text",
value: "Hello",
});
// => new message: Hello
messageReceived({
type: "image",
imageUrl: "...",
});
// => unknown message: image
Direct match
You can match directly to store api as well:
import { split, createStore, createEvent, createApi } from "effector";
const messageReceived = createEvent();
const $textContent = createStore([]);
split({
source: messageReceived,
match: {
text: (msg) => msg.type === "text",
audio: (msg) => msg.type === "audio",
},
cases: createApi($textContent, {
text: (list, { value }) => [...list, value],
audio: (list, { duration }) => [...list, `audio ${duration} ms`],
__: (list) => [...list, "unknown message"],
}),
});
$textContent.watch((messages) => {
console.log(messages);
});
messageReceived({
type: "text",
value: "Hello",
});
// => ['Hello']
messageReceived({
type: "image",
imageUrl: "...",
});
// => ['Hello', 'unknown message']
messageReceived({
type: "audio",
duration: 500,
});
// => ['Hello', 'unknown message', 'audio 500 ms']
Cases with arrays of units
import { createEffect, createEvent, createStore, sample, split } from "effector";
const $verificationCode = createStore("12345")
const $error = createStore("");
const modalToInputUsername = createEvent();
const modalToAuthorizationMethod = createEvent();
const checkVerificationCodeFx = createEffect((code) => {
throw "500"
});
sample({
clock: verificationCodeSubmitted,
source: $verificationCode,
target: checkVerificationCodeFx
});
split({
source: checkVerificationCodeFx.failData,
match: (value) => (["400", "410"].includes(value) ? "verificationCodeError" : "serverError"),
cases: {
verificationCodeError: $verificationCodeError,
serverError: [$error, modalToAuthorizationMethod]
}
});
$error.updates.watch((value) => console.log("ERROR: " + value));
modalToAuthorizationMethod.watch(() => console.log("Modal window to the authorization method content."))
// => ERROR: 500
// => Modal window to the authorization method content.
split(source, match)
Formulae
split(source, match);
Arguments
source
: Unit which will trigger computation insplit
match
(Object): Schema of cases, which uses names of resulting events as keys, and matching function*((value) => Boolean)*
Returns
(Object) β Object, having keys, defined in match
argument, plus __
(two underscores) β which stands for default
(no matches met) case.
Examples
Basic
import { createEvent, split } from "effector";
const message = createEvent();
const messageByAuthor = split(message, {
bob: ({ user }) => user === "bob",
alice: ({ user }) => user === "alice",
});
messageByAuthor.bob.watch(({ text }) => {
console.log("[bob]: ", text);
});
messageByAuthor.alice.watch(({ text }) => {
console.log("[alice]: ", text);
});
message({ user: "bob", text: "Hello" });
// => [bob]: Hello
message({ user: "alice", text: "Hi bob" });
// => [alice]: Hi bob
/* default case, triggered if no one condition met */
const { __: guest } = messageByAuthor;
guest.watch(({ text }) => {
console.log("[guest]: ", text);
});
message({ user: "unregistered", text: "hi" });
// => [guest]: hi
Only the first met match will trigger resulting event
Another
import { createEvent, split } from "effector";
const message = createEvent();
const { short, long, medium } = split(message, {
short: (m) => m.length <= 5,
medium: (m) => m.length > 5 && m.length <= 10,
long: (m) => m.length > 10,
});
short.watch((m) => console.log(`short message '${m}'`));
medium.watch((m) => console.log(`medium message '${m}'`));
long.watch((m) => console.log(`long message '${m}'`));
message("Hello, Bob!");
// => long message 'Hello, Bob!'
message("Hi!");
// => short message 'Hi!'
split({ source, clock?, match, cases })
It works the same as split with cases, however computations in split
will be started after clock
is triggered.
Formulae
split({source, clock?, match, cases})
Arguments
TBD
Examples
import { createStore, createEvent, createEffect, split } from "effector";
const options = ["save", "delete", "forward"];
const $message = createStore({ id: 1, text: "Bring me a cup of coffee, please!" });
const $mode = createStore("");
const selectedMessageOption = createEvent();
const saveMessageFx = createEffect(() => "save");
const forwardMessageFx = createEffect(() => "forward");
const deleteMessageFx = createEffect(() => "delete");
$mode.on(selectedMessageOption, (mode, opt) => options.find((item) => item === opt) ?? mode);
split({
source: $message,
clock: selectedMessageOption,
match: $mode,
cases: {
save: saveMessageFx,
delete: deleteMessageFx,
forward: forwardMessageFx,
},
});
selectedMessageOption("delet"); // nothing happens
selectedMessageOption("delete");