@xstate/react 4.0.0-beta.4 → 4.0.0-beta.5
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/dist/declarations/src/index.d.ts +6 -6
- package/dist/{useConstant-720f1662.cjs.prod.js → useConstant-2ee82f84.cjs.js} +1 -1
- package/dist/useConstant-ae6dceac.development.cjs.js +35 -0
- package/dist/useConstant-bac83df4.development.esm.js +13 -0
- package/dist/useConstant-c7ec0fdd.esm.js +13 -0
- package/dist/xstate-react.cjs.js +178 -4
- package/dist/{xstate-react.cjs.prod.js → xstate-react.development.cjs.js} +55 -65
- package/dist/xstate-react.development.esm.js +159 -0
- package/dist/xstate-react.esm.js +47 -79
- package/fsm/dist/xstate-react-fsm.cjs.js +65 -4
- package/fsm/dist/xstate-react-fsm.development.cjs.js +74 -0
- package/fsm/dist/xstate-react-fsm.development.esm.js +65 -0
- package/fsm/dist/xstate-react-fsm.esm.js +30 -42
- package/package.json +27 -3
- package/dist/declarations/src/useConstant.d.ts +0 -1
- package/dist/useConstant-23e96eea.cjs.dev.js +0 -91
- package/dist/useConstant-9bbaf12a.esm.js +0 -68
- package/dist/xstate-react.cjs.dev.js +0 -213
- package/fsm/dist/xstate-react-fsm.cjs.dev.js +0 -80
- package/fsm/dist/xstate-react-fsm.cjs.prod.js +0 -127
package/dist/xstate-react.esm.js
CHANGED
|
@@ -1,50 +1,36 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useEffect,
|
|
2
|
+
import { useEffect, useCallback } from 'react';
|
|
3
3
|
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector';
|
|
4
4
|
import { toObserver, InterpreterStatus, interpret } from 'xstate';
|
|
5
|
-
import {
|
|
5
|
+
import { u as useConstant } from './useConstant-c7ec0fdd.esm.js';
|
|
6
6
|
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect';
|
|
7
|
-
import
|
|
7
|
+
import 'xstate/actors';
|
|
8
8
|
|
|
9
9
|
function useIdleInterpreter(machine, options) {
|
|
10
|
-
|
|
11
|
-
var _useState = useState(machine),
|
|
12
|
-
_useState2 = _slicedToArray(_useState, 1),
|
|
13
|
-
initialMachine = _useState2[0];
|
|
14
|
-
if (machine.config !== initialMachine.config) {
|
|
15
|
-
console.warn("Actor logic has changed between renders. This is not supported and may lead to invalid snapshots.");
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
var actorRef = useConstant(function () {
|
|
10
|
+
const actorRef = useConstant(() => {
|
|
19
11
|
return interpret(machine, options);
|
|
20
12
|
});
|
|
21
13
|
|
|
22
14
|
// TODO: consider using `useAsapEffect` that would do this in `useInsertionEffect` is that's available
|
|
23
|
-
useIsomorphicLayoutEffect(
|
|
15
|
+
useIsomorphicLayoutEffect(() => {
|
|
24
16
|
actorRef.behavior.options = machine.options;
|
|
25
17
|
});
|
|
26
18
|
return actorRef;
|
|
27
19
|
}
|
|
28
|
-
function useActorRef(machine) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
var _ref$ = _ref[0],
|
|
33
|
-
options = _ref$ === void 0 ? {} : _ref$,
|
|
34
|
-
observerOrListener = _ref[1];
|
|
35
|
-
var service = useIdleInterpreter(machine, options);
|
|
36
|
-
useEffect(function () {
|
|
20
|
+
function useActorRef(machine, ...[options = {}, observerOrListener]) {
|
|
21
|
+
const service = useIdleInterpreter(machine, options);
|
|
22
|
+
useEffect(() => {
|
|
37
23
|
if (!observerOrListener) {
|
|
38
24
|
return;
|
|
39
25
|
}
|
|
40
|
-
|
|
41
|
-
return
|
|
26
|
+
let sub = service.subscribe(toObserver(observerOrListener));
|
|
27
|
+
return () => {
|
|
42
28
|
sub.unsubscribe();
|
|
43
29
|
};
|
|
44
30
|
}, [observerOrListener]);
|
|
45
|
-
useEffect(
|
|
31
|
+
useEffect(() => {
|
|
46
32
|
service.start();
|
|
47
|
-
return
|
|
33
|
+
return () => {
|
|
48
34
|
service.stop();
|
|
49
35
|
service.status = InterpreterStatus.NotStarted;
|
|
50
36
|
service._initState();
|
|
@@ -56,29 +42,24 @@ function useActorRef(machine) {
|
|
|
56
42
|
function identity(a) {
|
|
57
43
|
return a;
|
|
58
44
|
}
|
|
59
|
-
|
|
45
|
+
const isEqual = (prevState, nextState) => {
|
|
60
46
|
return prevState === nextState || nextState.changed === false;
|
|
61
47
|
};
|
|
62
|
-
function useActor(behavior) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (isActorRef(behavior)) {
|
|
66
|
-
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.");
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
var actorRef = useIdleInterpreter(behavior, options);
|
|
70
|
-
var getSnapshot = useCallback(function () {
|
|
48
|
+
function useActor(behavior, options = {}) {
|
|
49
|
+
const actorRef = useIdleInterpreter(behavior, options);
|
|
50
|
+
const getSnapshot = useCallback(() => {
|
|
71
51
|
return actorRef.getSnapshot();
|
|
72
52
|
}, [actorRef]);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
unsubscribe
|
|
53
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
54
|
+
const {
|
|
55
|
+
unsubscribe
|
|
56
|
+
} = actorRef.subscribe(handleStoreChange);
|
|
76
57
|
return unsubscribe;
|
|
77
58
|
}, [actorRef]);
|
|
78
|
-
|
|
79
|
-
useEffect(
|
|
59
|
+
const actorSnapshot = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
60
|
+
useEffect(() => {
|
|
80
61
|
actorRef.start();
|
|
81
|
-
return
|
|
62
|
+
return () => {
|
|
82
63
|
actorRef.stop();
|
|
83
64
|
actorRef.status = InterpreterStatus.NotStarted;
|
|
84
65
|
actorRef._initState();
|
|
@@ -90,30 +71,18 @@ function useActor(behavior) {
|
|
|
90
71
|
function defaultCompare(a, b) {
|
|
91
72
|
return a === b;
|
|
92
73
|
}
|
|
93
|
-
function useSelector(actor, selector) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
74
|
+
function useSelector(actor, selector, compare = defaultCompare) {
|
|
75
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
76
|
+
const {
|
|
77
|
+
unsubscribe
|
|
78
|
+
} = actor.subscribe(handleStoreChange);
|
|
98
79
|
return unsubscribe;
|
|
99
80
|
}, [actor]);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}, [actor]);
|
|
103
|
-
var selectedSnapshot = useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
81
|
+
const boundGetSnapshot = useCallback(() => actor.getSnapshot(), [actor]);
|
|
82
|
+
const selectedSnapshot = useSyncExternalStoreWithSelector(subscribe, boundGetSnapshot, boundGetSnapshot, selector, compare);
|
|
104
83
|
return selectedSnapshot;
|
|
105
84
|
}
|
|
106
85
|
|
|
107
|
-
function _typeof(obj) {
|
|
108
|
-
"@babel/helpers - typeof";
|
|
109
|
-
|
|
110
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
|
|
111
|
-
return typeof obj;
|
|
112
|
-
} : function (obj) {
|
|
113
|
-
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
114
|
-
}, _typeof(obj);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
86
|
// From https://github.com/reduxjs/react-redux/blob/720f0ba79236cdc3e1115f4ef9a7760a21784b48/src/utils/shallowEqual.ts
|
|
118
87
|
function is(x, y) {
|
|
119
88
|
if (x === y) {
|
|
@@ -124,13 +93,13 @@ function is(x, y) {
|
|
|
124
93
|
}
|
|
125
94
|
function shallowEqual(objA, objB) {
|
|
126
95
|
if (is(objA, objB)) return true;
|
|
127
|
-
if (
|
|
96
|
+
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
|
|
128
97
|
return false;
|
|
129
98
|
}
|
|
130
|
-
|
|
131
|
-
|
|
99
|
+
const keysA = Object.keys(objA);
|
|
100
|
+
const keysB = Object.keys(objB);
|
|
132
101
|
if (keysA.length !== keysB.length) return false;
|
|
133
|
-
for (
|
|
102
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
134
103
|
if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
|
|
135
104
|
return false;
|
|
136
105
|
}
|
|
@@ -139,28 +108,28 @@ function shallowEqual(objA, objB) {
|
|
|
139
108
|
}
|
|
140
109
|
|
|
141
110
|
function createActorContext(machine, interpreterOptions, observerOrListener) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
function Provider(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
111
|
+
const ReactContext = /*#__PURE__*/React.createContext(null);
|
|
112
|
+
const OriginalProvider = ReactContext.Provider;
|
|
113
|
+
function Provider({
|
|
114
|
+
children,
|
|
115
|
+
machine: providedMachine = machine
|
|
116
|
+
}) {
|
|
117
|
+
const actor = useActorRef(providedMachine, interpreterOptions, observerOrListener);
|
|
149
118
|
return /*#__PURE__*/React.createElement(OriginalProvider, {
|
|
150
119
|
value: actor,
|
|
151
|
-
children
|
|
120
|
+
children
|
|
152
121
|
});
|
|
153
122
|
}
|
|
154
|
-
Provider.displayName =
|
|
123
|
+
Provider.displayName = `ActorProvider(${machine.id})`;
|
|
155
124
|
function useContext() {
|
|
156
|
-
|
|
125
|
+
const actor = React.useContext(ReactContext);
|
|
157
126
|
if (!actor) {
|
|
158
|
-
throw new Error(
|
|
127
|
+
throw new Error(`You used a hook from "${Provider.displayName}" but it's not inside a <${Provider.displayName}> component.`);
|
|
159
128
|
}
|
|
160
129
|
return actor;
|
|
161
130
|
}
|
|
162
131
|
function useSelector$1(selector, compare) {
|
|
163
|
-
|
|
132
|
+
const actor = useContext();
|
|
164
133
|
return useSelector(actor, selector, compare);
|
|
165
134
|
}
|
|
166
135
|
return {
|
|
@@ -174,8 +143,7 @@ function createActorContext(machine, interpreterOptions, observerOrListener) {
|
|
|
174
143
|
*
|
|
175
144
|
* @deprecated Use `useActor(...)` instead.
|
|
176
145
|
*/
|
|
177
|
-
function useMachine(machine) {
|
|
178
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
146
|
+
function useMachine(machine, options = {}) {
|
|
179
147
|
return useActor(machine, options);
|
|
180
148
|
}
|
|
181
149
|
|
|
@@ -1,7 +1,68 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var fsm = require('@xstate/fsm');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var useIsomorphicLayoutEffect = require('use-isomorphic-layout-effect');
|
|
8
|
+
var withSelector = require('use-sync-external-store/shim/with-selector');
|
|
9
|
+
var useConstant = require('../../dist/useConstant-2ee82f84.cjs.js');
|
|
10
|
+
|
|
11
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
12
|
+
|
|
13
|
+
var useIsomorphicLayoutEffect__default = /*#__PURE__*/_interopDefault(useIsomorphicLayoutEffect);
|
|
14
|
+
|
|
15
|
+
function identity(a) {
|
|
16
|
+
return a;
|
|
7
17
|
}
|
|
18
|
+
function useMachine(stateMachine, options) {
|
|
19
|
+
const persistedStateRef = React.useRef();
|
|
20
|
+
const [service, queue] = useConstant.useConstant(() => {
|
|
21
|
+
const queue = [];
|
|
22
|
+
const service = fsm.interpret(fsm.createMachine(stateMachine.config, options ? options : stateMachine._options));
|
|
23
|
+
const {
|
|
24
|
+
send
|
|
25
|
+
} = service;
|
|
26
|
+
service.send = event => {
|
|
27
|
+
if (service.status === fsm.InterpreterStatus.NotStarted) {
|
|
28
|
+
queue.push(event);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
send(event);
|
|
32
|
+
persistedStateRef.current = service.state;
|
|
33
|
+
};
|
|
34
|
+
return [service, queue];
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// TODO: consider using `useInsertionEffect` if available
|
|
38
|
+
useIsomorphicLayoutEffect__default["default"](() => {
|
|
39
|
+
if (options) {
|
|
40
|
+
service._machine._options = options;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const useServiceResult = useService(service);
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
service.start(persistedStateRef.current);
|
|
46
|
+
queue.forEach(service.send);
|
|
47
|
+
persistedStateRef.current = service.state;
|
|
48
|
+
return () => {
|
|
49
|
+
service.stop();
|
|
50
|
+
};
|
|
51
|
+
}, []);
|
|
52
|
+
return useServiceResult;
|
|
53
|
+
}
|
|
54
|
+
const isEqual = (_prevState, nextState) => nextState.changed === false;
|
|
55
|
+
function useService(service) {
|
|
56
|
+
const getSnapshot = React.useCallback(() => service.state, [service]);
|
|
57
|
+
const subscribe = React.useCallback(handleStoreChange => {
|
|
58
|
+
const {
|
|
59
|
+
unsubscribe
|
|
60
|
+
} = service.subscribe(handleStoreChange);
|
|
61
|
+
return unsubscribe;
|
|
62
|
+
}, [service]);
|
|
63
|
+
const storeSnapshot = withSelector.useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
64
|
+
return [storeSnapshot, service.send, service];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
exports.useMachine = useMachine;
|
|
68
|
+
exports.useService = useService;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var fsm = require('@xstate/fsm');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var useIsomorphicLayoutEffect = require('use-isomorphic-layout-effect');
|
|
8
|
+
var withSelector = require('use-sync-external-store/shim/with-selector');
|
|
9
|
+
var useConstant = require('../../dist/useConstant-ae6dceac.development.cjs.js');
|
|
10
|
+
|
|
11
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
12
|
+
|
|
13
|
+
var useIsomorphicLayoutEffect__default = /*#__PURE__*/_interopDefault(useIsomorphicLayoutEffect);
|
|
14
|
+
|
|
15
|
+
function identity(a) {
|
|
16
|
+
return a;
|
|
17
|
+
}
|
|
18
|
+
function useMachine(stateMachine, options) {
|
|
19
|
+
const persistedStateRef = React.useRef();
|
|
20
|
+
{
|
|
21
|
+
const [initialMachine] = React.useState(stateMachine);
|
|
22
|
+
if (stateMachine !== initialMachine) {
|
|
23
|
+
console.warn('Machine given to `useMachine` has changed between renders. This is not supported and might lead to unexpected results.\n' + 'Please make sure that you pass the same Machine as argument each time.');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const [service, queue] = useConstant.useConstant(() => {
|
|
27
|
+
const queue = [];
|
|
28
|
+
const service = fsm.interpret(fsm.createMachine(stateMachine.config, options ? options : stateMachine._options));
|
|
29
|
+
const {
|
|
30
|
+
send
|
|
31
|
+
} = service;
|
|
32
|
+
service.send = event => {
|
|
33
|
+
if (service.status === fsm.InterpreterStatus.NotStarted) {
|
|
34
|
+
queue.push(event);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
send(event);
|
|
38
|
+
persistedStateRef.current = service.state;
|
|
39
|
+
};
|
|
40
|
+
return [service, queue];
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// TODO: consider using `useInsertionEffect` if available
|
|
44
|
+
useIsomorphicLayoutEffect__default["default"](() => {
|
|
45
|
+
if (options) {
|
|
46
|
+
service._machine._options = options;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const useServiceResult = useService(service);
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
service.start(persistedStateRef.current);
|
|
52
|
+
queue.forEach(service.send);
|
|
53
|
+
persistedStateRef.current = service.state;
|
|
54
|
+
return () => {
|
|
55
|
+
service.stop();
|
|
56
|
+
};
|
|
57
|
+
}, []);
|
|
58
|
+
return useServiceResult;
|
|
59
|
+
}
|
|
60
|
+
const isEqual = (_prevState, nextState) => nextState.changed === false;
|
|
61
|
+
function useService(service) {
|
|
62
|
+
const getSnapshot = React.useCallback(() => service.state, [service]);
|
|
63
|
+
const subscribe = React.useCallback(handleStoreChange => {
|
|
64
|
+
const {
|
|
65
|
+
unsubscribe
|
|
66
|
+
} = service.subscribe(handleStoreChange);
|
|
67
|
+
return unsubscribe;
|
|
68
|
+
}, [service]);
|
|
69
|
+
const storeSnapshot = withSelector.useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
70
|
+
return [storeSnapshot, service.send, service];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
exports.useMachine = useMachine;
|
|
74
|
+
exports.useService = useService;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { interpret, createMachine, InterpreterStatus } from '@xstate/fsm';
|
|
2
|
+
import { useRef, useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect';
|
|
4
|
+
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector';
|
|
5
|
+
import { u as useConstant } from '../../dist/useConstant-bac83df4.development.esm.js';
|
|
6
|
+
|
|
7
|
+
function identity(a) {
|
|
8
|
+
return a;
|
|
9
|
+
}
|
|
10
|
+
function useMachine(stateMachine, options) {
|
|
11
|
+
const persistedStateRef = useRef();
|
|
12
|
+
{
|
|
13
|
+
const [initialMachine] = useState(stateMachine);
|
|
14
|
+
if (stateMachine !== initialMachine) {
|
|
15
|
+
console.warn('Machine given to `useMachine` has changed between renders. This is not supported and might lead to unexpected results.\n' + 'Please make sure that you pass the same Machine as argument each time.');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const [service, queue] = useConstant(() => {
|
|
19
|
+
const queue = [];
|
|
20
|
+
const service = interpret(createMachine(stateMachine.config, options ? options : stateMachine._options));
|
|
21
|
+
const {
|
|
22
|
+
send
|
|
23
|
+
} = service;
|
|
24
|
+
service.send = event => {
|
|
25
|
+
if (service.status === InterpreterStatus.NotStarted) {
|
|
26
|
+
queue.push(event);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
send(event);
|
|
30
|
+
persistedStateRef.current = service.state;
|
|
31
|
+
};
|
|
32
|
+
return [service, queue];
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// TODO: consider using `useInsertionEffect` if available
|
|
36
|
+
useIsomorphicLayoutEffect(() => {
|
|
37
|
+
if (options) {
|
|
38
|
+
service._machine._options = options;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const useServiceResult = useService(service);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
service.start(persistedStateRef.current);
|
|
44
|
+
queue.forEach(service.send);
|
|
45
|
+
persistedStateRef.current = service.state;
|
|
46
|
+
return () => {
|
|
47
|
+
service.stop();
|
|
48
|
+
};
|
|
49
|
+
}, []);
|
|
50
|
+
return useServiceResult;
|
|
51
|
+
}
|
|
52
|
+
const isEqual = (_prevState, nextState) => nextState.changed === false;
|
|
53
|
+
function useService(service) {
|
|
54
|
+
const getSnapshot = useCallback(() => service.state, [service]);
|
|
55
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
56
|
+
const {
|
|
57
|
+
unsubscribe
|
|
58
|
+
} = service.subscribe(handleStoreChange);
|
|
59
|
+
return unsubscribe;
|
|
60
|
+
}, [service]);
|
|
61
|
+
const storeSnapshot = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
62
|
+
return [storeSnapshot, service.send, service];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { useMachine, useService };
|
|
@@ -1,70 +1,58 @@
|
|
|
1
|
-
import { _ as _slicedToArray, u as useConstant } from '../../dist/useConstant-9bbaf12a.esm.js';
|
|
2
1
|
import { interpret, createMachine, InterpreterStatus } from '@xstate/fsm';
|
|
3
|
-
import { useRef,
|
|
2
|
+
import { useRef, useEffect, useCallback } from 'react';
|
|
4
3
|
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect';
|
|
5
4
|
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector';
|
|
5
|
+
import { u as useConstant } from '../../dist/useConstant-c7ec0fdd.esm.js';
|
|
6
6
|
|
|
7
7
|
function identity(a) {
|
|
8
8
|
return a;
|
|
9
9
|
}
|
|
10
10
|
function useMachine(stateMachine, options) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
send(event);
|
|
30
|
-
persistedStateRef.current = service.state;
|
|
31
|
-
};
|
|
32
|
-
return [service, queue];
|
|
33
|
-
}),
|
|
34
|
-
_useConstant2 = _slicedToArray(_useConstant, 2),
|
|
35
|
-
service = _useConstant2[0],
|
|
36
|
-
queue = _useConstant2[1];
|
|
11
|
+
const persistedStateRef = useRef();
|
|
12
|
+
const [service, queue] = useConstant(() => {
|
|
13
|
+
const queue = [];
|
|
14
|
+
const service = interpret(createMachine(stateMachine.config, options ? options : stateMachine._options));
|
|
15
|
+
const {
|
|
16
|
+
send
|
|
17
|
+
} = service;
|
|
18
|
+
service.send = event => {
|
|
19
|
+
if (service.status === InterpreterStatus.NotStarted) {
|
|
20
|
+
queue.push(event);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
send(event);
|
|
24
|
+
persistedStateRef.current = service.state;
|
|
25
|
+
};
|
|
26
|
+
return [service, queue];
|
|
27
|
+
});
|
|
37
28
|
|
|
38
29
|
// TODO: consider using `useInsertionEffect` if available
|
|
39
|
-
useIsomorphicLayoutEffect(
|
|
30
|
+
useIsomorphicLayoutEffect(() => {
|
|
40
31
|
if (options) {
|
|
41
32
|
service._machine._options = options;
|
|
42
33
|
}
|
|
43
34
|
});
|
|
44
|
-
|
|
45
|
-
useEffect(
|
|
35
|
+
const useServiceResult = useService(service);
|
|
36
|
+
useEffect(() => {
|
|
46
37
|
service.start(persistedStateRef.current);
|
|
47
38
|
queue.forEach(service.send);
|
|
48
39
|
persistedStateRef.current = service.state;
|
|
49
|
-
return
|
|
40
|
+
return () => {
|
|
50
41
|
service.stop();
|
|
51
42
|
};
|
|
52
43
|
}, []);
|
|
53
44
|
return useServiceResult;
|
|
54
45
|
}
|
|
55
|
-
|
|
56
|
-
return nextState.changed === false;
|
|
57
|
-
};
|
|
46
|
+
const isEqual = (_prevState, nextState) => nextState.changed === false;
|
|
58
47
|
function useService(service) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
unsubscribe = _service$subscribe.unsubscribe;
|
|
48
|
+
const getSnapshot = useCallback(() => service.state, [service]);
|
|
49
|
+
const subscribe = useCallback(handleStoreChange => {
|
|
50
|
+
const {
|
|
51
|
+
unsubscribe
|
|
52
|
+
} = service.subscribe(handleStoreChange);
|
|
65
53
|
return unsubscribe;
|
|
66
54
|
}, [service]);
|
|
67
|
-
|
|
55
|
+
const storeSnapshot = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity, isEqual);
|
|
68
56
|
return [storeSnapshot, service.send, service];
|
|
69
57
|
}
|
|
70
58
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xstate/react",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.5",
|
|
4
4
|
"description": "XState tools for React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"state",
|
|
@@ -19,17 +19,41 @@
|
|
|
19
19
|
"module": "dist/xstate-react.esm.js",
|
|
20
20
|
"exports": {
|
|
21
21
|
"./fsm": {
|
|
22
|
+
"types": {
|
|
23
|
+
"import": "./fsm/dist/xstate-react-fsm.cjs.mjs",
|
|
24
|
+
"default": "./fsm/dist/xstate-react-fsm.cjs.js"
|
|
25
|
+
},
|
|
26
|
+
"development": {
|
|
27
|
+
"module": "./fsm/dist/xstate-react-fsm.development.esm.js",
|
|
28
|
+
"import": "./fsm/dist/xstate-react-fsm.development.cjs.mjs",
|
|
29
|
+
"default": "./fsm/dist/xstate-react-fsm.development.cjs.js"
|
|
30
|
+
},
|
|
22
31
|
"module": "./fsm/dist/xstate-react-fsm.esm.js",
|
|
23
32
|
"import": "./fsm/dist/xstate-react-fsm.cjs.mjs",
|
|
24
33
|
"default": "./fsm/dist/xstate-react-fsm.cjs.js"
|
|
25
34
|
},
|
|
26
35
|
".": {
|
|
36
|
+
"types": {
|
|
37
|
+
"import": "./dist/xstate-react.cjs.mjs",
|
|
38
|
+
"default": "./dist/xstate-react.cjs.js"
|
|
39
|
+
},
|
|
40
|
+
"development": {
|
|
41
|
+
"module": "./dist/xstate-react.development.esm.js",
|
|
42
|
+
"import": "./dist/xstate-react.development.cjs.mjs",
|
|
43
|
+
"default": "./dist/xstate-react.development.cjs.js"
|
|
44
|
+
},
|
|
27
45
|
"module": "./dist/xstate-react.esm.js",
|
|
28
46
|
"import": "./dist/xstate-react.cjs.mjs",
|
|
29
47
|
"default": "./dist/xstate-react.cjs.js"
|
|
30
48
|
},
|
|
31
49
|
"./package.json": "./package.json"
|
|
32
50
|
},
|
|
51
|
+
"imports": {
|
|
52
|
+
"#is-development": {
|
|
53
|
+
"development": "./src/true.ts",
|
|
54
|
+
"default": "./src/false.ts"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
33
57
|
"types": "dist/xstate-react.cjs.d.ts",
|
|
34
58
|
"sideEffects": false,
|
|
35
59
|
"files": [
|
|
@@ -47,7 +71,7 @@
|
|
|
47
71
|
"peerDependencies": {
|
|
48
72
|
"@xstate/fsm": "^3.0.0-beta.2",
|
|
49
73
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
|
50
|
-
"xstate": "^5.0.0-beta.
|
|
74
|
+
"xstate": "^5.0.0-beta.13"
|
|
51
75
|
},
|
|
52
76
|
"peerDependenciesMeta": {
|
|
53
77
|
"@xstate/fsm": {
|
|
@@ -72,7 +96,7 @@
|
|
|
72
96
|
"jsdom-global": "^3.0.2",
|
|
73
97
|
"react": "^18.0.0",
|
|
74
98
|
"react-dom": "^18.0.0",
|
|
75
|
-
"xstate": "5.0.0-beta.
|
|
99
|
+
"xstate": "5.0.0-beta.13"
|
|
76
100
|
},
|
|
77
101
|
"preconstruct": {
|
|
78
102
|
"entrypoints": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function useConstant<T>(fn: () => T): T;
|