UNPKG

1.97 kBJavaScriptView Raw
1"use strict";
2
3exports.__esModule = true;
4exports.default = useStateAsync;
5
6var _react = require("react");
7
8/**
9 * A hook that mirrors `useState` in function and API, expect that setState
10 * calls return a promise that resolves after the state has been set (in an effect).
11 *
12 * This is _similar_ to the second callback in classy setState calls, but fires later.
13 *
14 * ```ts
15 * const [counter, setState] = useStateAsync(1);
16 *
17 * const handleIncrement = async () => {
18 * await setState(2);
19 * doWorkRequiringCurrentState()
20 * }
21 * ```
22 *
23 * @param initialState initialize with some state value same as `useState`
24 */
25function useStateAsync(initialState) {
26 var _useState = (0, _react.useState)(initialState),
27 state = _useState[0],
28 setState = _useState[1];
29
30 var resolvers = (0, _react.useRef)([]);
31 (0, _react.useEffect)(function () {
32 resolvers.current.forEach(function (resolve) {
33 return resolve(state);
34 });
35 resolvers.current.length = 0;
36 }, [state]);
37 var setStateAsync = (0, _react.useCallback)(function (update) {
38 return new Promise(function (resolve, reject) {
39 setState(function (prevState) {
40 try {
41 var nextState; // ugly instanceof for typescript
42
43 if (update instanceof Function) {
44 nextState = update(prevState);
45 } else {
46 nextState = update;
47 } // If state does not change, we must resolve the promise because
48 // react won't re-render and effect will not resolve. If there are already
49 // resolvers queued, then it should be safe to assume an update will happen
50
51
52 if (!resolvers.current.length && Object.is(nextState, prevState)) {
53 resolve(nextState);
54 } else {
55 resolvers.current.push(resolve);
56 }
57
58 return nextState;
59 } catch (e) {
60 reject(e);
61 throw e;
62 }
63 });
64 });
65 }, [setState]);
66 return [state, setStateAsync];
67}
\No newline at end of file