Repository: pmndrs/valtio
Pull request #60 (2020-12-30 14:59:05)

Properly check for value for promise result
Valtio currently does not work well with falsy values. This PR is a small improvement to allow falsy values to not be ignored.

Use case:
```js
const state = proxy({ user: user().catch(e => null) })
```

codesandbox[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/pmndrs/valtio/pr/60/builds/86896) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 9289466152b3d19051b5d9885fcf569b4944f35f:

|Sandbox| Source |
|--|--|
|[React](https://codesandbox.io/s/react-wcjcq)| Configuration |
|[React Typescript](https://codesandbox.io/s/react-typescript-t6sus)| Configuration |

zvictor: The problem can be seen in action at

https://github.com/zvictor/faugra/blob/dcb41d832b78afadadd63438dec91d63288078d3/examples/with-proxied-authentication/pages/index.js#L16-L30

If `user === null`, the `snapshot` object doesn't get updated.
zvictor: there you go :)

Patch:
diff --git a/.size-snapshot.json b/.size-snapshot.json
index cbc8cf8..19932a7 100644
--- a/.size-snapshot.json
+++ b/.size-snapshot.json
@@ -1,8 +1,8 @@
 {
   "index.js": {
-    "bundled": 9899,
-    "minified": 4642,
-    "gzipped": 1702,
+    "bundled": 9901,
+    "minified": 4644,
+    "gzipped": 1706,
     "treeshaked": {
       "rollup": {
         "code": 137,
@@ -14,19 +14,19 @@
     }
   },
   "index.cjs.js": {
-    "bundled": 10745,
-    "minified": 5098,
-    "gzipped": 1803
+    "bundled": 10747,
+    "minified": 5100,
+    "gzipped": 1807
   },
   "index.iife.js": {
-    "bundled": 11416,
-    "minified": 4029,
-    "gzipped": 1604
+    "bundled": 11418,
+    "minified": 4031,
+    "gzipped": 1606
   },
   "vanilla.js": {
-    "bundled": 5470,
-    "minified": 2750,
-    "gzipped": 1019,
+    "bundled": 5472,
+    "minified": 2752,
+    "gzipped": 1022,
     "treeshaked": {
       "rollup": {
         "code": 22,
@@ -38,9 +38,9 @@
     }
   },
   "vanilla.cjs.js": {
-    "bundled": 5930,
-    "minified": 3025,
-    "gzipped": 1118
+    "bundled": 5932,
+    "minified": 3027,
+    "gzipped": 1122
   },
   "utils.js": {
     "bundled": 3391,
diff --git a/src/vanilla.ts b/src/vanilla.ts
index a92a393..c2beaec 100644
--- a/src/vanilla.ts
+++ b/src/vanilla.ts
@@ -75,7 +75,7 @@ export const proxy = <T extends object>(initialObject: T = {} as T): T => {
           if (!isSupportedObject(value)) {
             snapshot[key] = value
           } else if (value instanceof Promise) {
-            if ((value as any)[PROMISE_RESULT]) {
+            if (PROMISE_RESULT in (value as any)) {
               snapshot[key] = (value as any)[PROMISE_RESULT]
             } else {
               const errorOrPromise = (value as any)[PROMISE_ERROR] || value


Test patch:
diff --git a/tests/async.test.tsx b/tests/async.test.tsx
index 9da29cc..abc913b 100644
--- a/tests/async.test.tsx
+++ b/tests/async.test.tsx
@@ -69,3 +69,34 @@ it('delayed object', async () => {
   await findByText('loading')
   await findByText('text: hello')
 })
+
+it('delayed falsy value', async () => {
+  const state = proxy<any>({ value: true })
+  const delayedValue = () => {
+    state.value = sleep(10).then(() => null)
+  }
+
+  const Counter: React.FC = () => {
+    const snapshot = useProxy(state)
+    return (
+      <>
+        <div>value: {String(snapshot.value)}</div>
+        <button onClick={delayedValue}>button</button>
+      </>
+    )
+  }
+
+  const { getByText, findByText } = render(
+    <StrictMode>
+      <Suspense fallback="loading">
+        <Counter />
+      </Suspense>
+    </StrictMode>
+  )
+
+  await findByText('value: true')
+
+  fireEvent.click(getByText('button'))
+  await findByText('loading')
+  await findByText('value: null')
+})