-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathuseObservableEffect.ts
More file actions
77 lines (74 loc) · 2.94 KB
/
Copy pathuseObservableEffect.ts
File metadata and controls
77 lines (74 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { useLayoutEffect, useState } from 'react';
import type { FlowSubject } from '../FlowSubject.js';
import type { Action, Effect, ActionType, ExtractAction } from '../types/index.js';
/**
* React hook that attaches a side-effect to a {@link FlowSubject}, filtered
* by a specific action type.
*
* @template S - The state type.
* @template A - The action type.
* @template TType - The specific action type to listen for.
* @param subject - The `FlowSubject` to attach the effect to.
* @param type - The action type string to filter on.
* @param effect - The effect function invoked for each matching action.
*/
export function useObservableEffect<
S,
A extends Action = Action,
TType extends ActionType<A> = ActionType<A>,
>(subject: FlowSubject<S, A>, type: TType, effect?: Effect<ExtractAction<A, TType>, S>): void;
/**
* React hook that attaches a side-effect to a {@link FlowSubject} for all actions.
*
* @template S - The state type.
* @template A - The action type.
* @param subject - The `FlowSubject` to attach the effect to.
* @param effect - The effect function invoked for each dispatched action.
*/
export function useObservableEffect<S, A extends Action = Action>(
subject: FlowSubject<S, A>,
effect: Effect<A, S>,
): void;
/**
* Applies a side-effect to a {@link FlowSubject}.
*
* The subscription is created on mount (or when `subject` changes) and torn down
* on unmount. Pass an action type string as the second argument to filter effects
* to a single action type, or pass the effect function directly to handle all actions.
*
* **Important:** The effect may return a new action, which will be dispatched back
* into the subject. Be careful to avoid infinite loops.
*
* @template S - The state type.
* @template A - The action type.
* @template TType - The action type string, when filtering to a single action type.
* @param subject - The `FlowSubject` to attach the effect to.
* @param effectOrType - Either the effect function (for all actions) or an action type string to filter by.
* @param effect - The effect function invoked for the filtered action type, when `effectOrType` is a type string.
*
* @example
* ```tsx
* useObservableEffect(subject, 'fetchUser', (action, state) => {
* return { type: 'setLoading', payload: true };
* });
* ```
*/
export function useObservableEffect<
S,
A extends Action = Action,
TType extends ActionType<A> = ActionType<A>,
>(
subject: FlowSubject<S, A>,
effectOrType: Effect<A, S> | TType,
effect?: Effect<ExtractAction<A, TType>, S>,
): void {
const [type] = useState(() => (typeof effectOrType === 'string' ? effectOrType : undefined));
const [fn] = useState(() => effect ?? effectOrType);
useLayoutEffect(() => {
const subscription = type
? subject.addEffect(type, fn as Effect<ExtractAction<A, TType>, S>)
: subject.addEffect(fn as Effect<A, S>);
return () => subscription.unsubscribe();
}, [subject, type, fn]);
}
export default useObservableEffect;