@xstate/react 4.0.0-alpha.2 → 4.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -8
- package/dist/declarations/src/createActorContext.d.ts +16 -9
- package/dist/declarations/src/index.d.ts +6 -7
- package/dist/declarations/src/useActor.d.ts +2 -3
- package/dist/declarations/src/useActorRef.d.ts +3 -0
- package/dist/declarations/src/useMachine.d.ts +8 -9
- package/dist/xstate-react.cjs.d.mts +2 -0
- package/dist/xstate-react.cjs.d.mts.map +1 -0
- package/dist/xstate-react.cjs.d.ts +1 -0
- package/dist/xstate-react.cjs.d.ts.map +1 -0
- package/dist/xstate-react.cjs.js +214 -4
- package/dist/xstate-react.cjs.mjs +8 -0
- package/dist/xstate-react.development.cjs.js +220 -0
- package/dist/xstate-react.development.cjs.mjs +8 -0
- package/dist/xstate-react.development.esm.js +189 -0
- package/dist/xstate-react.esm.js +118 -253
- package/package.json +21 -21
- package/dist/declarations/src/fsm.d.ts +0 -3
- package/dist/declarations/src/types.d.ts +0 -15
- package/dist/declarations/src/useConstant.d.ts +0 -1
- package/dist/declarations/src/useInterpret.d.ts +0 -12
- package/dist/declarations/src/useSpawn.d.ts +0 -9
- package/dist/useConstant-0013a606.esm.js +0 -68
- package/dist/useConstant-c09b427a.cjs.prod.js +0 -15
- package/dist/useConstant-ff65b597.cjs.dev.js +0 -71
- package/dist/xstate-react.cjs.dev.js +0 -335
- package/dist/xstate-react.cjs.prod.js +0 -327
- package/fsm/dist/xstate-react-fsm.cjs.d.ts +0 -1
- package/fsm/dist/xstate-react-fsm.cjs.dev.js +0 -87
- package/fsm/dist/xstate-react-fsm.cjs.js +0 -7
- package/fsm/dist/xstate-react-fsm.cjs.prod.js +0 -134
- package/fsm/dist/xstate-react-fsm.esm.js +0 -78
- package/fsm/package.json +0 -4
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useEffect, useState, useCallback } from 'react';
|
|
3
|
+
import { useSyncExternalStore } from 'use-sync-external-store/shim';
|
|
4
|
+
import { toObserver, createActor } from 'xstate';
|
|
5
|
+
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect';
|
|
6
|
+
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector';
|
|
7
|
+
|
|
8
|
+
const forEachActor = (actorRef, callback) => {
|
|
9
|
+
callback(actorRef);
|
|
10
|
+
const children = actorRef.getSnapshot().children;
|
|
11
|
+
if (children) {
|
|
12
|
+
Object.values(children).forEach(child => {
|
|
13
|
+
forEachActor(child, callback);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function stopRootWithRehydration(actorRef) {
|
|
18
|
+
// persist state here in a custom way allows us to persist inline actors and to preserve actor references
|
|
19
|
+
// we do it to avoid setState in useEffect when the effect gets "reconnected"
|
|
20
|
+
// this currently only happens in Strict Effects but it simulates the Offscreen aka Activity API
|
|
21
|
+
// it also just allows us to end up with a somewhat more predictable behavior for the users
|
|
22
|
+
const persistedSnapshots = [];
|
|
23
|
+
forEachActor(actorRef, ref => {
|
|
24
|
+
persistedSnapshots.push([ref, ref.getSnapshot()]);
|
|
25
|
+
// muting observers allow us to avoid `useSelector` from being notified about the stopped state
|
|
26
|
+
// React reconnects its subscribers (from the useSyncExternalStore) on its own
|
|
27
|
+
// and userland subscibers should basically always do the same anyway
|
|
28
|
+
// as each subscription should have its own cleanup logic and that should be called each such reconnect
|
|
29
|
+
ref.observers = new Set();
|
|
30
|
+
});
|
|
31
|
+
actorRef.stop();
|
|
32
|
+
persistedSnapshots.forEach(([ref, snapshot]) => {
|
|
33
|
+
ref._processingStatus = 0;
|
|
34
|
+
ref._state = snapshot;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function useIdleActor(logic, options) {
|
|
39
|
+
let [[currentConfig, actorRef], setCurrent] = useState(() => {
|
|
40
|
+
const actorRef = createActor(logic, options);
|
|
41
|
+
return [logic.config, actorRef];
|
|
42
|
+
});
|
|
43
|
+
if (logic.config !== currentConfig) {
|
|
44
|
+
const newActorRef = createActor(logic, {
|
|
45
|
+
...options,
|
|
46
|
+
state: actorRef.getPersistedState({
|
|
47
|
+
__unsafeAllowInlineActors: true
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
setCurrent([logic.config, newActorRef]);
|
|
51
|
+
actorRef = newActorRef;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// TODO: consider using `useAsapEffect` that would do this in `useInsertionEffect` is that's available
|
|
55
|
+
useIsomorphicLayoutEffect(() => {
|
|
56
|
+
actorRef.logic.implementations = logic.implementations;
|
|
57
|
+
});
|
|
58
|
+
return actorRef;
|
|
59
|
+
}
|
|
60
|
+
function useActorRef(machine, options = {}, observerOrListener) {
|
|
61
|
+
const actorRef = useIdleActor(machine, options);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!observerOrListener) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
let sub = actorRef.subscribe(toObserver(observerOrListener));
|
|
67
|
+
return () => {
|
|
68
|
+
sub.unsubscribe();
|
|
69
|
+
};
|
|
70
|
+
}, [observerOrListener]);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
actorRef.start();
|
|
73
|
+
return () => {
|
|
74
|
+
stopRootWithRehydration(actorRef);
|
|
75
|
+
};
|
|
76
|
+
}, [actorRef]);
|
|
77
|
+
return actorRef;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function useActor(logic, options = {}) {
|
|
81
|
+
if (!!logic && 'send' in logic && typeof logic.send === 'function') {
|
|
82
|
+
throw new Error(`useActor() expects actor logic (e.g. a machine), but received an ActorRef. Use the useSelector(actorRef, ...) hook instead to read the ActorRef's snapshot.`);
|
|
83
|
+
}
|
|
84
|
+
const actorRef = useIdleActor(logic, options);
|
|
85
|
+
const getSnapshot = useCallback(() => {
|
|
86
|
+
return actorRef.getSnapshot();
|
|
87
|
+
}, [actorRef]);
|
|
88
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
89
|
+
const {
|
|
90
|
+
unsubscribe
|
|
91
|
+
} = actorRef.subscribe(handleStoreChange);
|
|
92
|
+
return unsubscribe;
|
|
93
|
+
}, [actorRef]);
|
|
94
|
+
const actorSnapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
actorRef.start();
|
|
97
|
+
return () => {
|
|
98
|
+
stopRootWithRehydration(actorRef);
|
|
99
|
+
};
|
|
100
|
+
}, [actorRef]);
|
|
101
|
+
return [actorSnapshot, actorRef.send, actorRef];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function defaultCompare(a, b) {
|
|
105
|
+
return a === b;
|
|
106
|
+
}
|
|
107
|
+
function useSelector(actor, selector, compare = defaultCompare) {
|
|
108
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
109
|
+
const {
|
|
110
|
+
unsubscribe
|
|
111
|
+
} = actor.subscribe(handleStoreChange);
|
|
112
|
+
return unsubscribe;
|
|
113
|
+
}, [actor]);
|
|
114
|
+
const boundGetSnapshot = useCallback(() => actor.getSnapshot(), [actor]);
|
|
115
|
+
const selectedSnapshot = useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
116
|
+
return selectedSnapshot;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// From https://github.com/reduxjs/react-redux/blob/720f0ba79236cdc3e1115f4ef9a7760a21784b48/src/utils/shallowEqual.ts
|
|
120
|
+
function is(x, y) {
|
|
121
|
+
if (x === y) {
|
|
122
|
+
return x !== 0 || y !== 0 || 1 / x === 1 / y;
|
|
123
|
+
} else {
|
|
124
|
+
return x !== x && y !== y;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function shallowEqual(objA, objB) {
|
|
128
|
+
if (is(objA, objB)) return true;
|
|
129
|
+
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const keysA = Object.keys(objA);
|
|
133
|
+
const keysB = Object.keys(objB);
|
|
134
|
+
if (keysA.length !== keysB.length) return false;
|
|
135
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
136
|
+
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function createActorContext(actorLogic, interpreterOptions) {
|
|
144
|
+
const ReactContext = /*#__PURE__*/React.createContext(null);
|
|
145
|
+
const OriginalProvider = ReactContext.Provider;
|
|
146
|
+
function Provider({
|
|
147
|
+
children,
|
|
148
|
+
logic: providedLogic = actorLogic,
|
|
149
|
+
machine,
|
|
150
|
+
options: providedOptions = interpreterOptions
|
|
151
|
+
}) {
|
|
152
|
+
if (machine) {
|
|
153
|
+
throw new Error(`The "machine" prop has been deprecated. Please use "logic" instead.`);
|
|
154
|
+
}
|
|
155
|
+
const actor = useActorRef(providedLogic, providedOptions);
|
|
156
|
+
return /*#__PURE__*/React.createElement(OriginalProvider, {
|
|
157
|
+
value: actor,
|
|
158
|
+
children
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// TODO: add properties to actor ref to make more descriptive
|
|
163
|
+
Provider.displayName = `ActorProvider`;
|
|
164
|
+
function useContext() {
|
|
165
|
+
const actor = React.useContext(ReactContext);
|
|
166
|
+
if (!actor) {
|
|
167
|
+
throw new Error(`You used a hook from "${Provider.displayName}" but it's not inside a <${Provider.displayName}> component.`);
|
|
168
|
+
}
|
|
169
|
+
return actor;
|
|
170
|
+
}
|
|
171
|
+
function useSelector$1(selector, compare) {
|
|
172
|
+
const actor = useContext();
|
|
173
|
+
return useSelector(actor, selector, compare);
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
Provider: Provider,
|
|
177
|
+
useActorRef: useContext,
|
|
178
|
+
useSelector: useSelector$1
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @alias useActor
|
|
184
|
+
*/
|
|
185
|
+
function useMachine(machine, options = {}) {
|
|
186
|
+
return useActor(machine, options);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export { createActorContext, shallowEqual, useActor, useActorRef, useMachine, useSelector };
|
package/dist/xstate-react.esm.js
CHANGED
|
@@ -1,208 +1,118 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { useEffect, useState, useCallback
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useEffect, useState, useCallback } from 'react';
|
|
3
|
+
import { useSyncExternalStore } from 'use-sync-external-store/shim';
|
|
4
|
+
import { toObserver, createActor } from 'xstate';
|
|
3
5
|
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect';
|
|
4
6
|
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector';
|
|
5
|
-
import { toObserver, InterpreterStatus, interpret } from 'xstate';
|
|
6
|
-
import { useSyncExternalStore } from 'use-sync-external-store/shim';
|
|
7
|
-
|
|
8
|
-
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
9
|
-
if (source == null) return {};
|
|
10
|
-
var target = {};
|
|
11
|
-
var sourceKeys = Object.keys(source);
|
|
12
|
-
var key, i;
|
|
13
|
-
for (i = 0; i < sourceKeys.length; i++) {
|
|
14
|
-
key = sourceKeys[i];
|
|
15
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
16
|
-
target[key] = source[key];
|
|
17
|
-
}
|
|
18
|
-
return target;
|
|
19
|
-
}
|
|
20
7
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
key = sourceSymbolKeys[i];
|
|
29
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
30
|
-
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
31
|
-
target[key] = source[key];
|
|
32
|
-
}
|
|
8
|
+
const forEachActor = (actorRef, callback) => {
|
|
9
|
+
callback(actorRef);
|
|
10
|
+
const children = actorRef.getSnapshot().children;
|
|
11
|
+
if (children) {
|
|
12
|
+
Object.values(children).forEach(child => {
|
|
13
|
+
forEachActor(child, callback);
|
|
14
|
+
});
|
|
33
15
|
}
|
|
34
|
-
|
|
16
|
+
};
|
|
17
|
+
function stopRootWithRehydration(actorRef) {
|
|
18
|
+
// persist state here in a custom way allows us to persist inline actors and to preserve actor references
|
|
19
|
+
// we do it to avoid setState in useEffect when the effect gets "reconnected"
|
|
20
|
+
// this currently only happens in Strict Effects but it simulates the Offscreen aka Activity API
|
|
21
|
+
// it also just allows us to end up with a somewhat more predictable behavior for the users
|
|
22
|
+
const persistedSnapshots = [];
|
|
23
|
+
forEachActor(actorRef, ref => {
|
|
24
|
+
persistedSnapshots.push([ref, ref.getSnapshot()]);
|
|
25
|
+
// muting observers allow us to avoid `useSelector` from being notified about the stopped state
|
|
26
|
+
// React reconnects its subscribers (from the useSyncExternalStore) on its own
|
|
27
|
+
// and userland subscibers should basically always do the same anyway
|
|
28
|
+
// as each subscription should have its own cleanup logic and that should be called each such reconnect
|
|
29
|
+
ref.observers = new Set();
|
|
30
|
+
});
|
|
31
|
+
actorRef.stop();
|
|
32
|
+
persistedSnapshots.forEach(([ref, snapshot]) => {
|
|
33
|
+
ref._processingStatus = 0;
|
|
34
|
+
ref._state = snapshot;
|
|
35
|
+
});
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return
|
|
38
|
+
function useIdleActor(logic, options) {
|
|
39
|
+
let [[currentConfig, actorRef], setCurrent] = useState(() => {
|
|
40
|
+
const actorRef = createActor(logic, options);
|
|
41
|
+
return [logic.config, actorRef];
|
|
41
42
|
});
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
43
|
+
if (logic.config !== currentConfig) {
|
|
44
|
+
const newActorRef = createActor(logic, {
|
|
45
|
+
...options,
|
|
46
|
+
state: actorRef.getPersistedState({
|
|
47
|
+
__unsafeAllowInlineActors: true
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
setCurrent([logic.config, newActorRef]);
|
|
51
|
+
actorRef = newActorRef;
|
|
49
52
|
}
|
|
50
|
-
var actors = options.actors,
|
|
51
|
-
guards = options.guards,
|
|
52
|
-
actions = options.actions,
|
|
53
|
-
delays = options.delays,
|
|
54
|
-
interpreterOptions = _objectWithoutProperties(options, _excluded);
|
|
55
|
-
var service = useConstant(function () {
|
|
56
|
-
var machineConfig = {
|
|
57
|
-
guards: guards,
|
|
58
|
-
actions: actions,
|
|
59
|
-
actors: actors,
|
|
60
|
-
delays: delays
|
|
61
|
-
};
|
|
62
|
-
var machineWithConfig = machine.provide(machineConfig);
|
|
63
|
-
return interpret(machineWithConfig, interpreterOptions);
|
|
64
|
-
});
|
|
65
53
|
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Object.assign(service.behavior.options.guards, guards);
|
|
72
|
-
Object.assign(service.behavior.options.actors, actors);
|
|
73
|
-
Object.assign(service.behavior.options.delays, delays);
|
|
74
|
-
}, [actions, guards, actors, delays]);
|
|
75
|
-
return service;
|
|
54
|
+
// TODO: consider using `useAsapEffect` that would do this in `useInsertionEffect` is that's available
|
|
55
|
+
useIsomorphicLayoutEffect(() => {
|
|
56
|
+
actorRef.logic.implementations = logic.implementations;
|
|
57
|
+
});
|
|
58
|
+
return actorRef;
|
|
76
59
|
}
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
var _ref$ = _ref[0],
|
|
82
|
-
options = _ref$ === void 0 ? {} : _ref$,
|
|
83
|
-
observerOrListener = _ref[1];
|
|
84
|
-
var service = useIdleInterpreter(getMachine, options);
|
|
85
|
-
useEffect(function () {
|
|
60
|
+
function useActorRef(machine, options = {}, observerOrListener) {
|
|
61
|
+
const actorRef = useIdleActor(machine, options);
|
|
62
|
+
useEffect(() => {
|
|
86
63
|
if (!observerOrListener) {
|
|
87
64
|
return;
|
|
88
65
|
}
|
|
89
|
-
|
|
90
|
-
return
|
|
66
|
+
let sub = actorRef.subscribe(toObserver(observerOrListener));
|
|
67
|
+
return () => {
|
|
91
68
|
sub.unsubscribe();
|
|
92
69
|
};
|
|
93
70
|
}, [observerOrListener]);
|
|
94
|
-
useEffect(
|
|
95
|
-
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
service.status = InterpreterStatus.NotStarted;
|
|
99
|
-
service._initState();
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
actorRef.start();
|
|
73
|
+
return () => {
|
|
74
|
+
stopRootWithRehydration(actorRef);
|
|
100
75
|
};
|
|
101
|
-
}, []);
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function identity(a) {
|
|
106
|
-
return a;
|
|
107
|
-
}
|
|
108
|
-
var isEqual = function isEqual(prevState, nextState) {
|
|
109
|
-
return prevState === nextState || nextState.changed === false;
|
|
110
|
-
};
|
|
111
|
-
function useMachine(getMachine) {
|
|
112
|
-
for (var _len = arguments.length, _ref = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
113
|
-
_ref[_key - 1] = arguments[_key];
|
|
114
|
-
}
|
|
115
|
-
var _ref$ = _ref[0],
|
|
116
|
-
options = _ref$ === void 0 ? {} : _ref$;
|
|
117
|
-
// using `useIdleInterpreter` allows us to subscribe to the service *before* we start it
|
|
118
|
-
// so we don't miss any notifications
|
|
119
|
-
var service = useIdleInterpreter(getMachine, options);
|
|
120
|
-
var getSnapshot = useCallback(function () {
|
|
121
|
-
return service.getSnapshot();
|
|
122
|
-
}, [service]);
|
|
123
|
-
var subscribe = useCallback(function (handleStoreChange) {
|
|
124
|
-
var _service$subscribe = service.subscribe(handleStoreChange),
|
|
125
|
-
unsubscribe = _service$subscribe.unsubscribe;
|
|
126
|
-
return unsubscribe;
|
|
127
|
-
}, [service]);
|
|
128
|
-
var storeSnapshot = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
129
|
-
useEffect(function () {
|
|
130
|
-
service.start();
|
|
131
|
-
return function () {
|
|
132
|
-
service.stop();
|
|
133
|
-
service.status = InterpreterStatus.NotStarted;
|
|
134
|
-
service._initState();
|
|
135
|
-
};
|
|
136
|
-
}, []);
|
|
137
|
-
return [storeSnapshot, service.send, service];
|
|
76
|
+
}, [actorRef]);
|
|
77
|
+
return actorRef;
|
|
138
78
|
}
|
|
139
79
|
|
|
140
|
-
function useActor(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
unsubscribe = _actorRef$subscribe.unsubscribe;
|
|
144
|
-
return unsubscribe;
|
|
145
|
-
}, [actorRef]);
|
|
146
|
-
var boundGetSnapshot = useCallback(function () {
|
|
80
|
+
function useActor(logic, options = {}) {
|
|
81
|
+
const actorRef = useIdleActor(logic, options);
|
|
82
|
+
const getSnapshot = useCallback(() => {
|
|
147
83
|
return actorRef.getSnapshot();
|
|
148
84
|
}, [actorRef]);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
85
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
86
|
+
const {
|
|
87
|
+
unsubscribe
|
|
88
|
+
} = actorRef.subscribe(handleStoreChange);
|
|
89
|
+
return unsubscribe;
|
|
90
|
+
}, [actorRef]);
|
|
91
|
+
const actorSnapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
actorRef.start();
|
|
94
|
+
return () => {
|
|
95
|
+
stopRootWithRehydration(actorRef);
|
|
96
|
+
};
|
|
152
97
|
}, [actorRef]);
|
|
153
|
-
return [
|
|
98
|
+
return [actorSnapshot, actorRef.send, actorRef];
|
|
154
99
|
}
|
|
155
100
|
|
|
156
101
|
function defaultCompare(a, b) {
|
|
157
102
|
return a === b;
|
|
158
103
|
}
|
|
159
|
-
function useSelector(actor, selector) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
104
|
+
function useSelector(actor, selector, compare = defaultCompare) {
|
|
105
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
106
|
+
const {
|
|
107
|
+
unsubscribe
|
|
108
|
+
} = actor.subscribe(handleStoreChange);
|
|
164
109
|
return unsubscribe;
|
|
165
110
|
}, [actor]);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}, [actor]);
|
|
169
|
-
var selectedSnapshot = useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
111
|
+
const boundGetSnapshot = useCallback(() => actor.getSnapshot(), [actor]);
|
|
112
|
+
const selectedSnapshot = useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
170
113
|
return selectedSnapshot;
|
|
171
114
|
}
|
|
172
115
|
|
|
173
|
-
/**
|
|
174
|
-
* React hook that spawns an `ActorRef` with the specified `behavior`.
|
|
175
|
-
* The returned `ActorRef` can be used with the `useActor(actorRef)` hook.
|
|
176
|
-
*
|
|
177
|
-
* @param behavior The actor behavior to spawn
|
|
178
|
-
* @returns An ActorRef with the specified `behavior`
|
|
179
|
-
*/
|
|
180
|
-
function useSpawn(behavior) {
|
|
181
|
-
var actorRef = useConstant(function () {
|
|
182
|
-
// TODO: figure out what to do about the name argument
|
|
183
|
-
return interpret(behavior);
|
|
184
|
-
});
|
|
185
|
-
useEffect(function () {
|
|
186
|
-
var _actorRef$start;
|
|
187
|
-
(_actorRef$start = actorRef.start) === null || _actorRef$start === void 0 ? void 0 : _actorRef$start.call(actorRef);
|
|
188
|
-
return function () {
|
|
189
|
-
var _stop, _ref;
|
|
190
|
-
(_stop = (_ref = actorRef).stop) === null || _stop === void 0 ? void 0 : _stop.call(_ref);
|
|
191
|
-
};
|
|
192
|
-
}, []);
|
|
193
|
-
return actorRef;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function _typeof(obj) {
|
|
197
|
-
"@babel/helpers - typeof";
|
|
198
|
-
|
|
199
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
|
|
200
|
-
return typeof obj;
|
|
201
|
-
} : function (obj) {
|
|
202
|
-
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
203
|
-
}, _typeof(obj);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
116
|
// From https://github.com/reduxjs/react-redux/blob/720f0ba79236cdc3e1115f4ef9a7760a21784b48/src/utils/shallowEqual.ts
|
|
207
117
|
function is(x, y) {
|
|
208
118
|
if (x === y) {
|
|
@@ -213,13 +123,13 @@ function is(x, y) {
|
|
|
213
123
|
}
|
|
214
124
|
function shallowEqual(objA, objB) {
|
|
215
125
|
if (is(objA, objB)) return true;
|
|
216
|
-
if (
|
|
126
|
+
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
217
127
|
return false;
|
|
218
128
|
}
|
|
219
|
-
|
|
220
|
-
|
|
129
|
+
const keysA = Object.keys(objA);
|
|
130
|
+
const keysB = Object.keys(objB);
|
|
221
131
|
if (keysA.length !== keysB.length) return false;
|
|
222
|
-
for (
|
|
132
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
223
133
|
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
|
|
224
134
|
return false;
|
|
225
135
|
}
|
|
@@ -227,95 +137,50 @@ function shallowEqual(objA, objB) {
|
|
|
227
137
|
return true;
|
|
228
138
|
}
|
|
229
139
|
|
|
230
|
-
function
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function _defineProperty(obj, key, value) {
|
|
247
|
-
key = _toPropertyKey(key);
|
|
248
|
-
if (key in obj) {
|
|
249
|
-
Object.defineProperty(obj, key, {
|
|
250
|
-
value: value,
|
|
251
|
-
enumerable: true,
|
|
252
|
-
configurable: true,
|
|
253
|
-
writable: true
|
|
254
|
-
});
|
|
255
|
-
} else {
|
|
256
|
-
obj[key] = value;
|
|
257
|
-
}
|
|
258
|
-
return obj;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function ownKeys(object, enumerableOnly) {
|
|
262
|
-
var keys = Object.keys(object);
|
|
263
|
-
if (Object.getOwnPropertySymbols) {
|
|
264
|
-
var symbols = Object.getOwnPropertySymbols(object);
|
|
265
|
-
enumerableOnly && (symbols = symbols.filter(function (sym) {
|
|
266
|
-
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
267
|
-
})), keys.push.apply(keys, symbols);
|
|
268
|
-
}
|
|
269
|
-
return keys;
|
|
270
|
-
}
|
|
271
|
-
function _objectSpread2(target) {
|
|
272
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
273
|
-
var source = null != arguments[i] ? arguments[i] : {};
|
|
274
|
-
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
|
|
275
|
-
_defineProperty(target, key, source[key]);
|
|
276
|
-
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
|
|
277
|
-
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
return target;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function createActorContext(machine, interpreterOptions, observerOrListener) {
|
|
284
|
-
var ReactContext = /*#__PURE__*/createContext(null);
|
|
285
|
-
var OriginalProvider = ReactContext.Provider;
|
|
286
|
-
function Provider(_ref) {
|
|
287
|
-
var children = _ref.children,
|
|
288
|
-
_ref$machine = _ref.machine,
|
|
289
|
-
providedMachine = _ref$machine === void 0 ? machine : _ref$machine,
|
|
290
|
-
options = _ref.options;
|
|
291
|
-
var actor = useInterpret(providedMachine, _objectSpread2(_objectSpread2({}, interpreterOptions), options), observerOrListener);
|
|
292
|
-
return /*#__PURE__*/createElement(OriginalProvider, {
|
|
140
|
+
function createActorContext(actorLogic, interpreterOptions) {
|
|
141
|
+
const ReactContext = /*#__PURE__*/React.createContext(null);
|
|
142
|
+
const OriginalProvider = ReactContext.Provider;
|
|
143
|
+
function Provider({
|
|
144
|
+
children,
|
|
145
|
+
logic: providedLogic = actorLogic,
|
|
146
|
+
machine,
|
|
147
|
+
options: providedOptions = interpreterOptions
|
|
148
|
+
}) {
|
|
149
|
+
if (machine) {
|
|
150
|
+
throw new Error(`The "machine" prop has been deprecated. Please use "logic" instead.`);
|
|
151
|
+
}
|
|
152
|
+
const actor = useActorRef(providedLogic, providedOptions);
|
|
153
|
+
return /*#__PURE__*/React.createElement(OriginalProvider, {
|
|
293
154
|
value: actor,
|
|
294
|
-
children
|
|
155
|
+
children
|
|
295
156
|
});
|
|
296
157
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
158
|
+
|
|
159
|
+
// TODO: add properties to actor ref to make more descriptive
|
|
160
|
+
Provider.displayName = `ActorProvider`;
|
|
161
|
+
function useContext() {
|
|
162
|
+
const actor = React.useContext(ReactContext);
|
|
300
163
|
if (!actor) {
|
|
301
|
-
throw new Error(
|
|
164
|
+
throw new Error(`You used a hook from "${Provider.displayName}" but it's not inside a <${Provider.displayName}> component.`);
|
|
302
165
|
}
|
|
303
166
|
return actor;
|
|
304
167
|
}
|
|
305
|
-
function useActor$1() {
|
|
306
|
-
var actor = useContext$1();
|
|
307
|
-
return useActor(actor);
|
|
308
|
-
}
|
|
309
168
|
function useSelector$1(selector, compare) {
|
|
310
|
-
|
|
169
|
+
const actor = useContext();
|
|
311
170
|
return useSelector(actor, selector, compare);
|
|
312
171
|
}
|
|
313
172
|
return {
|
|
314
173
|
Provider: Provider,
|
|
315
|
-
useActorRef: useContext
|
|
316
|
-
useActor: useActor$1,
|
|
174
|
+
useActorRef: useContext,
|
|
317
175
|
useSelector: useSelector$1
|
|
318
176
|
};
|
|
319
177
|
}
|
|
320
178
|
|
|
321
|
-
|
|
179
|
+
/**
|
|
180
|
+
* @alias useActor
|
|
181
|
+
*/
|
|
182
|
+
function useMachine(machine, options = {}) {
|
|
183
|
+
return useActor(machine, options);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export { createActorContext, shallowEqual, useActor, useActorRef, useMachine, useSelector };
|