diff --git a/CHANGELOG.md b/CHANGELOG.md
index 281f25dc46a..a3b3de3ebc8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -160,6 +160,9 @@
- Ensure `useMutation` passes a defined `errorPolicy` option into its underlying `ApolloClient.mutate()` call.
[@jamesreggio](https://github.com/jamesreggio) in [#5863](https://github.com/apollographql/apollo-client/pull/5863)
+- `useQuery`: Prevent new data re-render attempts during an existing render. This helps avoid React 16.13.0's "Cannot update a component from inside the function body of a different component" warning (https://github.com/facebook/react/pull/17099).
+ [@hwillson](https://github.com/hwillson) in [#6107](https://github.com/apollographql/apollo-client/pull/6107)
+
## Apollo Client 2.6.8
### Apollo Client (2.6.8)
diff --git a/package-lock.json b/package-lock.json
index 7804bca8927..47a7582e9c0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -720,9 +720,9 @@
"dev": true
},
"@types/react": {
- "version": "16.9.17",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.17.tgz",
- "integrity": "sha512-UP27In4fp4sWF5JgyV6pwVPAQM83Fj76JOcg02X5BZcpSu5Wx+fP9RMqc2v0ssBoQIFvD5JdKY41gjJJKmw6Bg==",
+ "version": "16.9.32",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.32.tgz",
+ "integrity": "sha512-fmejdp0CTH00mOJmxUPPbWCEBWPvRIL4m8r0qD+BSDUqmutPyGQCHifzMpMzdvZwROdEdL78IuZItntFWgPXHQ==",
"dev": true,
"requires": {
"@types/prop-types": "*",
@@ -730,9 +730,9 @@
}
},
"@types/react-dom": {
- "version": "16.9.4",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.4.tgz",
- "integrity": "sha512-fya9xteU/n90tda0s+FtN5Ym4tbgxpq/hb/Af24dvs6uYnYn+fspaxw5USlw0R8apDNwxsqumdRoCoKitckQqw==",
+ "version": "16.9.6",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.6.tgz",
+ "integrity": "sha512-S6ihtlPMDotrlCJE9ST1fRmYrQNNwfgL61UB4I1W7M6kPulUKx9fXAleW5zpdIjUQ4fTaaog8uERezjsGUj9HQ==",
"dev": true,
"requires": {
"@types/react": "*"
@@ -1746,9 +1746,9 @@
}
},
"csstype": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz",
- "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==",
+ "version": "2.6.10",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz",
+ "integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==",
"dev": true
},
"dashdash": {
@@ -2390,25 +2390,29 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"dev": true,
"optional": true,
"requires": {
@@ -2418,13 +2422,15 @@
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
"requires": {
@@ -2434,37 +2440,43 @@
},
"chownr": {
"version": "1.1.3",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==",
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true,
"optional": true
},
"debug": {
"version": "3.2.6",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"optional": true,
"requires": {
@@ -2473,25 +2485,29 @@
},
"deep-extend": {
"version": "0.6.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.7",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
"dev": true,
"optional": true,
"requires": {
@@ -2500,13 +2516,15 @@
},
"fs.realpath": {
"version": "1.0.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"optional": true,
"requires": {
@@ -2522,7 +2540,8 @@
},
"glob": {
"version": "7.1.6",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"optional": true,
"requires": {
@@ -2536,13 +2555,15 @@
},
"has-unicode": {
"version": "2.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"optional": true,
"requires": {
@@ -2551,7 +2572,8 @@
},
"ignore-walk": {
"version": "3.0.3",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
"dev": true,
"optional": true,
"requires": {
@@ -2560,7 +2582,8 @@
},
"inflight": {
"version": "1.0.6",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"optional": true,
"requires": {
@@ -2570,19 +2593,22 @@
},
"inherits": {
"version": "2.0.4",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
"requires": {
@@ -2591,13 +2617,15 @@
},
"isarray": {
"version": "1.0.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
"requires": {
@@ -2606,13 +2634,15 @@
},
"minimist": {
"version": "0.0.8",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
},
"minipass": {
"version": "2.9.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"dev": true,
"optional": true,
"requires": {
@@ -2622,7 +2652,8 @@
},
"minizlib": {
"version": "1.3.3",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"dev": true,
"optional": true,
"requires": {
@@ -2631,7 +2662,8 @@
},
"mkdirp": {
"version": "0.5.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
@@ -2640,13 +2672,15 @@
},
"ms": {
"version": "2.1.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true,
"optional": true
},
"needle": {
"version": "2.4.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==",
"dev": true,
"optional": true,
"requires": {
@@ -2657,7 +2691,8 @@
},
"node-pre-gyp": {
"version": "0.14.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==",
"dev": true,
"optional": true,
"requires": {
@@ -2675,7 +2710,8 @@
},
"nopt": {
"version": "4.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true,
"optional": true,
"requires": {
@@ -2685,7 +2721,8 @@
},
"npm-bundled": {
"version": "1.1.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
"dev": true,
"optional": true,
"requires": {
@@ -2694,13 +2731,15 @@
},
"npm-normalize-package-bin": {
"version": "1.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.4.7",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ==",
"dev": true,
"optional": true,
"requires": {
@@ -2710,7 +2749,8 @@
},
"npmlog": {
"version": "4.1.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"optional": true,
"requires": {
@@ -2722,19 +2762,22 @@
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
"requires": {
@@ -2743,19 +2786,22 @@
},
"os-homedir": {
"version": "1.0.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"optional": true,
"requires": {
@@ -2765,19 +2811,22 @@
},
"path-is-absolute": {
"version": "1.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.8",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true,
"optional": true,
"requires": {
@@ -2789,7 +2838,8 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
}
@@ -2797,7 +2847,8 @@
},
"readable-stream": {
"version": "2.3.6",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
"requires": {
@@ -2812,7 +2863,8 @@
},
"rimraf": {
"version": "2.7.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"optional": true,
"requires": {
@@ -2821,43 +2873,50 @@
},
"safe-buffer": {
"version": "5.1.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"semver": {
"version": "5.7.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
"requires": {
@@ -2868,7 +2927,8 @@
},
"string_decoder": {
"version": "1.1.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"optional": true,
"requires": {
@@ -2877,7 +2937,8 @@
},
"strip-ansi": {
"version": "3.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
"requires": {
@@ -2886,13 +2947,15 @@
},
"strip-json-comments": {
"version": "2.0.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.13",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
"dev": true,
"optional": true,
"requires": {
@@ -2907,13 +2970,15 @@
},
"util-deprecate": {
"version": "1.0.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.3",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"dev": true,
"optional": true,
"requires": {
@@ -2922,13 +2987,15 @@
},
"wrappy": {
"version": "1.0.2",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true,
"optional": true
},
"yallist": {
"version": "3.1.1",
- "bundled": true,
+ "resolved": false,
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true,
"optional": true
}
@@ -5657,9 +5724,9 @@
}
},
"react": {
- "version": "16.12.0",
- "resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz",
- "integrity": "sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA==",
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
+ "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
@@ -5668,15 +5735,15 @@
}
},
"react-dom": {
- "version": "16.12.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz",
- "integrity": "sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw==",
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
+ "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
- "scheduler": "^0.18.0"
+ "scheduler": "^0.19.1"
}
},
"react-is": {
@@ -6020,9 +6087,9 @@
"dev": true
},
"scheduler": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.18.0.tgz",
- "integrity": "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==",
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
+ "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
diff --git a/package.json b/package.json
index 7ee351383e4..2b5a23d8486 100644
--- a/package.json
+++ b/package.json
@@ -80,8 +80,8 @@
"@types/jest": "24.0.25",
"@types/lodash": "4.14.149",
"@types/node": "12.12.22",
- "@types/react": "16.9.17",
- "@types/react-dom": "16.9.4",
+ "@types/react": "^16.9.32",
+ "@types/react-dom": "^16.9.6",
"bundlesize": "0.18.0",
"codecov": "3.6.5",
"fetch-mock": "7.7.3",
@@ -90,8 +90,8 @@
"jest-junit": "8.0.0",
"lodash": "4.17.15",
"prop-types": "15.7.2",
- "react": "16.12.0",
- "react-dom": "16.12.0",
+ "react": "^16.13.1",
+ "react-dom": "^16.13.1",
"recast": "0.19.0",
"rimraf": "3.0.2",
"rollup": "1.31.1",
diff --git a/src/react/data/QueryData.ts b/src/react/data/QueryData.ts
index ffb76285383..6f1cf91aeed 100644
--- a/src/react/data/QueryData.ts
+++ b/src/react/data/QueryData.ts
@@ -24,29 +24,29 @@ import {
QueryTuple,
QueryLazyOptions,
ObservableQueryFields,
- LazyQueryResult
} from '../types/types';
import { OperationData } from './OperationData';
export class QueryData extends OperationData {
+ public onNewData: () => void;
+
private previousData: QueryPreviousData = {};
private currentObservable?: ObservableQuery;
private currentSubscription?: ObservableSubscription;
- private forceUpdate: any;
private runLazy: boolean = false;
private lazyOptions?: QueryLazyOptions;
constructor({
options,
context,
- forceUpdate
+ onNewData
}: {
options: QueryDataOptions;
context: any;
- forceUpdate: any;
+ onNewData: () => void;
}) {
super(options, context);
- this.forceUpdate = forceUpdate;
+ this.onNewData = onNewData;
}
public execute(): QueryResult {
@@ -86,25 +86,11 @@ export class QueryData extends OperationData {
return new Promise(resolve => this.startQuerySubscription(resolve));
}
- public afterExecute({
- queryResult,
- lazy = false,
- }: {
- queryResult: QueryResult | LazyQueryResult;
- lazy?: boolean;
- }) {
+ public afterExecute({ lazy = false }: { lazy?: boolean } = {}) {
this.isMounted = true;
if (!lazy || this.runLazy) {
- this.handleErrorOrCompleted(queryResult as QueryResult);
-
- // When the component is done rendering stored query errors, we'll
- // remove those errors from the `ObservableQuery` query store, so they
- // aren't re-displayed on subsequent (potentially error free)
- // requests/responses.
- setTimeout(() => {
- this.currentObservable?.resetQueryStoreErrors();
- });
+ this.handleErrorOrCompleted();
}
this.previousOptions = this.getOptions();
@@ -139,12 +125,15 @@ export class QueryData extends OperationData {
return options;
}
+ public ssrInitiated() {
+ return this.context && this.context.renderPromises;
+ }
+
private runLazyQuery = (options?: QueryLazyOptions) => {
this.cleanup();
-
this.runLazy = true;
this.lazyOptions = options;
- this.forceUpdate();
+ this.onNewData();
};
private getExecuteResult(): QueryResult {
@@ -154,7 +143,6 @@ export class QueryData extends OperationData {
};
private getExecuteSsrResult() {
- const treeRenderingInitiated = this.context && this.context.renderPromises;
const ssrDisabled = this.getOptions().ssr === false;
const fetchDisabled = this.refreshClient().client.disableNetworkFetches;
@@ -162,17 +150,21 @@ export class QueryData extends OperationData {
loading: true,
networkStatus: NetworkStatus.loading,
called: true,
- data: undefined
+ data: undefined,
+ stale: false,
+ client: this.client,
+ ...this.observableQueryFields(),
} as QueryResult;
// If SSR has been explicitly disabled, and this function has been called
// on the server side, return the default loading state.
- if (ssrDisabled && (treeRenderingInitiated || fetchDisabled)) {
+ if (ssrDisabled && (this.ssrInitiated() || fetchDisabled)) {
+ this.previousData.result = ssrLoading;
return ssrLoading;
}
let result;
- if (treeRenderingInitiated) {
+ if (this.ssrInitiated()) {
result =
this.context.renderPromises!.addQueryPromise(
this,
@@ -191,8 +183,7 @@ export class QueryData extends OperationData {
// Set the fetchPolicy to cache-first for network-only and cache-and-network
// fetches for server side renders.
if (
- this.context &&
- this.context.renderPromises &&
+ this.ssrInitiated() &&
(options.fetchPolicy === 'network-only' ||
options.fetchPolicy === 'cache-and-network')
) {
@@ -210,8 +201,8 @@ export class QueryData extends OperationData {
// See if there is an existing observable that was used to fetch the same
// data and if so, use it instead since it will contain the proper queryId
// to fetch the result set. This is used during SSR.
- if (this.context && this.context.renderPromises) {
- this.currentObservable = this.context.renderPromises.getSSRObservable(
+ if (this.ssrInitiated()) {
+ this.currentObservable = this.context!.renderPromises!.getSSRObservable(
this.getOptions()
);
}
@@ -227,8 +218,8 @@ export class QueryData extends OperationData {
...observableQueryOptions
});
- if (this.context && this.context.renderPromises) {
- this.context.renderPromises.registerSSRObservable(
+ if (this.ssrInitiated()) {
+ this.context!.renderPromises!.registerSSRObservable(
this.currentObservable,
observableQueryOptions
);
@@ -269,10 +260,11 @@ export class QueryData extends OperationData {
// When new data is received, and it doesn't match the data that was used
// during the last `QueryData.execute` call (and ultimately the last query
// component render), trigger the `onNewData` callback. If not specified,
- // `onNewData` will trigger the `forceUpdate` function, which leads to a
- // query component re-render.
- private startQuerySubscription(onNewData: () => void = this.forceUpdate) {
+ // `onNewData` will fallback to the default `QueryData.onNewData` function
+ // (which usually leads to a query component re-render).
+ private startQuerySubscription(onNewData: () => void = this.onNewData) {
if (this.currentSubscription || this.getOptions().skip) return;
+
this.currentSubscription = this.currentObservable!.subscribe({
next: ({ loading, networkStatus, data }) => {
const previousResult = this.previousData.result;
@@ -424,14 +416,22 @@ export class QueryData extends OperationData {
this.setOptions(options, true);
this.previousData.loading =
this.previousData.result && this.previousData.result.loading || false;
- return this.previousData.result = result;
+ this.previousData.result = result;
+
+ // Any query errors that exist are now available in `result`, so we'll
+ // remove the original errors from the `ObservableQuery` query store to
+ // make sure they aren't re-displayed on subsequent (potentially error
+ // free) requests/responses.
+ this.currentObservable && this.currentObservable.resetQueryStoreErrors();
+
+ return result;
}
- private handleErrorOrCompleted({
- data,
- loading,
- error,
- }: QueryResult) {
+ private handleErrorOrCompleted() {
+ if (!this.currentObservable || !this.previousData.result) return;
+
+ const { data, loading, error } = this.previousData.result;
+
if (!loading) {
const { query, variables, onCompleted, onError } = this.getOptions();
diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx
index b06a6220432..ede6758fb21 100644
--- a/src/react/hooks/__tests__/useQuery.test.tsx
+++ b/src/react/hooks/__tests__/useQuery.test.tsx
@@ -14,7 +14,7 @@ import { useQuery } from '../useQuery';
import { requireReactLazily } from '../../react';
const React = requireReactLazily();
-const { useState, useReducer } = React;
+const { useState, useReducer, Fragment } = React;
describe('useQuery Hook', () => {
const CAR_QUERY: DocumentNode = gql`
@@ -320,6 +320,61 @@ describe('useQuery Hook', () => {
})
);
});
+
+ it('should not error when forcing an update with React >= 16.13.0', async () => {
+ let wasUpdateErrorLogged = false;
+ const consoleError = console.error;
+ console.error = (msg: string) => {
+ console.log(msg);
+ wasUpdateErrorLogged = msg.indexOf('Cannot update a component') > -1;
+ };
+
+ const CAR_MOCKS = [1, 2, 3, 4, 5, 6].map(something => ({
+ request: {
+ query: CAR_QUERY,
+ variables: { something }
+ },
+ result: { data: CAR_RESULT_DATA },
+ delay: 1000
+ }));
+
+ let renderCount = 0;
+
+ const InnerComponent = ({ something }: any) => {
+ const { loading, data } = useQuery(CAR_QUERY, {
+ fetchPolicy: 'network-only',
+ variables: { something }
+ });
+ if (loading) return null;
+ expect(wasUpdateErrorLogged).toBeFalsy();
+ expect(data).toEqual(CAR_RESULT_DATA);
+ renderCount += 1;
+ return null;
+ };
+
+ function WrapperComponent({ something }: any) {
+ const { loading } = useQuery(CAR_QUERY, {
+ variables: { something }
+ });
+ return loading ? null : ;
+ }
+
+ render(
+
+
+
+
+
+
+
+ );
+
+ await wait(() => {
+ expect(renderCount).toBe(3);
+ }).finally(() => {
+ console.error = consoleError;
+ });
+ });
});
describe('Polling', () => {
@@ -650,7 +705,7 @@ describe('useQuery Hook', () => {
expect(error).toBeDefined();
expect(error!.message).toEqual('GraphQL error: forced error');
setTimeout(() => {
- forceUpdate(0);
+ forceUpdate();
});
break;
case 2:
@@ -713,7 +768,7 @@ describe('useQuery Hook', () => {
expect(error).toBeDefined();
expect(error!.message).toEqual('GraphQL error: forced error');
setTimeout(() => {
- forceUpdate(0);
+ forceUpdate();
});
break;
case 2:
diff --git a/src/react/hooks/utils/useBaseQuery.ts b/src/react/hooks/utils/useBaseQuery.ts
index 96d4a83e098..ff315a5830d 100644
--- a/src/react/hooks/utils/useBaseQuery.ts
+++ b/src/react/hooks/utils/useBaseQuery.ts
@@ -24,19 +24,36 @@ export function useBaseQuery(
const updatedOptions = options ? { ...options, query } : { query };
const queryDataRef = useRef>();
-
- if (!queryDataRef.current) {
- queryDataRef.current = new QueryData({
+ const queryData =
+ queryDataRef.current ||
+ new QueryData({
options: updatedOptions as QueryDataOptions,
context,
- forceUpdate
+ onNewData() {
+ if (!queryData.ssrInitiated()) {
+ // When new data is received from the `QueryData` object, we want to
+ // force a re-render to make sure the new data is displayed. We can't
+ // force that re-render if we're already rendering however so to be
+ // safe we'll trigger the re-render in a microtask.
+ Promise.resolve().then(forceUpdate);
+ } else {
+ // If we're rendering on the server side we can force an update at
+ // any point.
+ forceUpdate();
+ }
+ }
});
- }
- const queryData = queryDataRef.current;
queryData.setOptions(updatedOptions);
queryData.context = context;
+ // SSR won't trigger the effect hook below that stores the current
+ // `QueryData` instance for future renders, so we'll handle that here if
+ // the current render is happening server side.
+ if (queryData.ssrInitiated() && !queryDataRef.current) {
+ queryDataRef.current = queryData;
+ }
+
// `onError` and `onCompleted` callback functions will not always have a
// stable identity, so we'll exclude them from the memoization key to
// prevent `afterExecute` from being triggered un-necessarily.
@@ -59,16 +76,22 @@ export function useBaseQuery(
? (result as QueryTuple)[1]
: (result as QueryResult);
- useEffect(() => queryData.afterExecute({ queryResult, lazy }), [
+ useEffect(() => {
+ // We only need one instance of the `QueryData` class, so we'll store it
+ // as a ref to make it available on subsequent renders.
+ if (!queryDataRef.current) {
+ queryDataRef.current = queryData;
+ }
+
+ return () => queryData.cleanup();
+ }, []);
+
+ useEffect(() => queryData.afterExecute({ lazy }), [
queryResult.loading,
queryResult.networkStatus,
queryResult.error,
- queryResult.data
+ queryResult.data,
]);
- useEffect(() => {
- return () => queryData.cleanup();
- }, []);
-
return result;
}
diff --git a/src/react/types/types.ts b/src/react/types/types.ts
index 9804419a993..1c83fd9c190 100644
--- a/src/react/types/types.ts
+++ b/src/react/types/types.ts
@@ -107,7 +107,7 @@ export interface QueryPreviousData {
client?: ApolloClient