graphql-react
Advanced tools
Comparing version 11.2.0 to 12.0.0
# graphql-react changelog | ||
## 12.0.0 | ||
### Major | ||
- Concurrent GraphQL operations with the same cache key no longer share the first request. | ||
- The `GraphQL` instance property `operations` type has changed: | ||
```diff | ||
- object<GraphQLCacheKey, Promise<GraphQLCacheValue>> | ||
+ object<GraphQLCacheKey, Array<Promise<GraphQLCacheValue>>> | ||
``` | ||
### Patch | ||
- Updated dev dependencies. | ||
- Improved the test utility `promisifyEvent` function. | ||
- Test the the `GraphQL` instance method `operate` option `reloadOnLoad` in isolation. | ||
- Test better the order of the `GraphQL` instance method `operate` triggered events. | ||
- Refactored the `GraphQL` instance method `operate` to eliminate the `GraphQL` private instance method `fetch` and reduce the chance of race conditions in consumer code. | ||
- Reduced the number of promises created by the `GraphQL` instance method `operate` when the `reloadOnLoad` and `reloadOnLoad` options are `false`. | ||
- Added a code example for how to await all loading GraphQL operations. | ||
- Used consistent JSDoc types for promises that resolve `void`. | ||
- Tweaked JSDoc. | ||
- Tweaked changelog entries. | ||
## 11.2.0 | ||
@@ -172,3 +197,3 @@ | ||
- Added a `useGraphQL` options guide for common situations. | ||
- Test `GraphQL.operate()` with both `reloadOnLoad` and `resetOnLoad` options true. | ||
- Test the `GraphQL` instance method `operate` with both `reloadOnLoad` and `resetOnLoad` options `true`. | ||
- Use string `FormData` field names, as some `FormData` polyfills don't coerce numbers like native implementations do. | ||
@@ -175,0 +200,0 @@ - Test files in variables result in appropriate fetch options for a valid [GraphQL multipart request](https://github.com/jaydenseric/graphql-multipart-request-spec). |
{ | ||
"name": "graphql-react", | ||
"version": "11.2.0", | ||
"version": "12.0.0", | ||
"description": "A GraphQL client for React using modern context and hooks APIs that is lightweight (< 3.5 KB size limited) but powerful; the first Relay and Apollo alternative with server side rendering.", | ||
@@ -78,10 +78,10 @@ "license": "MIT", | ||
"coverage-node": "^3.0.0", | ||
"eslint": "^7.9.0", | ||
"eslint": "^7.10.0", | ||
"eslint-config-env": "^15.0.1", | ||
"eslint-config-prettier": "^6.11.0", | ||
"eslint-plugin-import": "^2.22.0", | ||
"eslint-plugin-jsdoc": "^30.5.1", | ||
"eslint-config-prettier": "^6.12.0", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-jsdoc": "^30.6.3", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-prettier": "^3.1.4", | ||
"eslint-plugin-react": "^7.20.6", | ||
"eslint-plugin-react": "^7.21.3", | ||
"eslint-plugin-react-hooks": "^4.1.2", | ||
@@ -97,3 +97,3 @@ "fetch-blob": "^2.1.1", | ||
"node-fetch": "^3.0.0-beta.9", | ||
"prettier": "^2.1.1", | ||
"prettier": "^2.1.2", | ||
"react": "^16.13.1", | ||
@@ -100,0 +100,0 @@ "react-dom": "^16.13.1", |
@@ -244,3 +244,3 @@ ![graphql-react logo](https://cdn.jsdelivr.net/gh/jaydenseric/graphql-react@0.1.0/graphql-react-logo.svg) | ||
Loads or reuses an already loading GraphQL operation in [GraphQL operations](#graphql-instance-property-operations). Emits a [`GraphQL`](#class-graphql) instance `fetch` event if an already loading operation isn’t reused, and a `cache` event once it’s loaded into the [GraphQL cache](#graphql-instance-property-cache). | ||
Loads a GraphQL operation, visible in [GraphQL operations](#graphql-instance-property-operations). Emits a [`GraphQL`](#class-graphql) [`fetch`](#graphql-event-fetch) event once the [`fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API) request has been initiated and the map of loading [GraphQL operations](#graphql-instance-property-operations) has been updated, and a [`GraphQL`](#class-graphql) [`cache`](#graphql-event-cache) event once it’s loaded into the [GraphQL cache](#graphql-instance-property-cache). | ||
@@ -333,6 +333,14 @@ | Parameter | Type | Description | | ||
A map of loading GraphQL operations. You probably don’t need to interact with this unless you’re implementing a server side rendering framework. | ||
A map of loading [GraphQL operations](#type-graphqloperation), listed under their [GraphQL cache](#graphql-instance-property-cache) [key](#type-graphqlcachekey) in the order they were initiated. You probably don’t need to interact with this unless you’re implementing a server side rendering framework. | ||
**Type:** object<[GraphQLCacheKey](#type-graphqlcachekey), Promise<[GraphQLCacheValue](#type-graphqlcachevalue)>> | ||
**Type:** object<[GraphQLCacheKey](#type-graphqlcachekey), Array<Promise<[GraphQLCacheValue](#type-graphqlcachevalue)>>> | ||
##### Examples | ||
_How to await all loading [GraphQL operations](#graphql-instance-property-operations)._ | ||
> ```js | ||
> await Promise.all(Object.values(graphql.operations).flat()); | ||
> ``` | ||
#### GraphQL event cache | ||
@@ -979,3 +987,3 @@ | ||
GraphQL operations are cached under hashes of their [`fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API) options. Multiple operations with the same hash share the same loading status and cache value. | ||
GraphQL operations are cached under hashes of their [`fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API) options. | ||
@@ -982,0 +990,0 @@ [`fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API), HTTP, parse and GraphQL errors can be cached, and therefore server side rendered and transported to the client for hydration and initial render. |
@@ -7,2 +7,4 @@ 'use strict'; | ||
const arrayFlat = require('../universal/private/arrayFlat'); | ||
module.exports = async function ssr( | ||
@@ -23,6 +25,6 @@ graphql, | ||
const string = render(node); | ||
const operations = Object.values(graphql.operations); | ||
const cacheValuePromises = arrayFlat(Object.values(graphql.operations)); | ||
if (operations.length) { | ||
await Promise.all(operations); | ||
if (cacheValuePromises.length) { | ||
await Promise.all(cacheValuePromises); | ||
return recurse(); | ||
@@ -29,0 +31,0 @@ } else { |
@@ -42,7 +42,18 @@ 'use strict'; | ||
this.fetch = function (_ref2, cacheKey) { | ||
var url = _ref2.url, | ||
options = _objectWithoutPropertiesLoose(_ref2, ['url']); | ||
var fetchResponse; | ||
this.operate = function (_ref2) { | ||
var operation = _ref2.operation, | ||
fetchOptionsOverride = _ref2.fetchOptionsOverride, | ||
_ref2$cacheKeyCreator = _ref2.cacheKeyCreator, | ||
cacheKeyCreator = | ||
_ref2$cacheKeyCreator === void 0 ? hashObject : _ref2$cacheKeyCreator, | ||
reloadOnLoad = _ref2.reloadOnLoad, | ||
resetOnLoad = _ref2.resetOnLoad; | ||
if (typeof cacheKeyCreator !== 'function') | ||
throw new TypeError( | ||
'operate() option “cacheKeyCreator” must be a function.' | ||
); | ||
if (reloadOnLoad && resetOnLoad) | ||
throw new TypeError( | ||
'operate() options “reloadOnLoad” and “resetOnLoad” can’t both be true.' | ||
); | ||
var fetcher = | ||
@@ -56,46 +67,84 @@ typeof fetch === 'function' | ||
}; | ||
var fetchOptions = graphqlFetchOptions(operation); | ||
if (fetchOptionsOverride) fetchOptionsOverride(fetchOptions); | ||
var url = fetchOptions.url, | ||
options = _objectWithoutPropertiesLoose(fetchOptions, ['url']); | ||
var cacheKey = cacheKeyCreator(fetchOptions); | ||
var resolveOperationsUpdated; | ||
var operationsUpdatedPromise = new Promise(function (resolve) { | ||
resolveOperationsUpdated = resolve; | ||
}); | ||
var responsePromise = fetcher(url, options); | ||
var fetchResponse; | ||
var cacheValue = {}; | ||
var cacheValuePromise = fetcher(url, options) | ||
.then( | ||
function (response) { | ||
fetchResponse = response; | ||
if (!response.ok) | ||
cacheValue.httpError = { | ||
status: response.status, | ||
statusText: response.statusText, | ||
}; | ||
return response.json().then( | ||
function (_ref3) { | ||
var errors = _ref3.errors, | ||
data = _ref3.data; | ||
if (!errors && !data) | ||
cacheValue.parseError = 'Malformed payload.'; | ||
if (errors) cacheValue.graphQLErrors = errors; | ||
if (data) cacheValue.data = data; | ||
}, | ||
function (_ref4) { | ||
var message = _ref4.message; | ||
cacheValue.parseError = message; | ||
} | ||
var cacheValuePromise = operationsUpdatedPromise.then(function () { | ||
return responsePromise | ||
.then( | ||
function (response) { | ||
fetchResponse = response; | ||
if (!response.ok) | ||
cacheValue.httpError = { | ||
status: response.status, | ||
statusText: response.statusText, | ||
}; | ||
return response.json().then( | ||
function (_ref3) { | ||
var errors = _ref3.errors, | ||
data = _ref3.data; | ||
if (!errors && !data) | ||
cacheValue.parseError = 'Malformed payload.'; | ||
if (errors) cacheValue.graphQLErrors = errors; | ||
if (data) cacheValue.data = data; | ||
}, | ||
function (_ref4) { | ||
var message = _ref4.message; | ||
cacheValue.parseError = message; | ||
} | ||
); | ||
}, | ||
function (_ref5) { | ||
var message = _ref5.message; | ||
cacheValue.fetchError = message; | ||
} | ||
) | ||
.then(function () { | ||
if (_this.operations[cacheKey].length > 1) { | ||
var operationIndex = _this.operations[cacheKey].indexOf( | ||
cacheValuePromise | ||
); | ||
if (operationIndex) | ||
return Promise.all( | ||
_this.operations[cacheKey].slice(0, operationIndex) | ||
); | ||
} | ||
}) | ||
.then(function () { | ||
_this.cache[cacheKey] = cacheValue; | ||
_this.operations[cacheKey].splice( | ||
_this.operations[cacheKey].indexOf(cacheValuePromise) >>> 0, | ||
1 | ||
); | ||
}, | ||
function (_ref5) { | ||
var message = _ref5.message; | ||
cacheValue.fetchError = message; | ||
} | ||
) | ||
.then(function () { | ||
_this.cache[cacheKey] = cacheValue; | ||
delete _this.operations[cacheKey]; | ||
_this.emit('cache', { | ||
cacheKey: cacheKey, | ||
cacheValue: cacheValue, | ||
response: fetchResponse, | ||
if (!_this.operations[cacheKey].length) | ||
delete _this.operations[cacheKey]; | ||
_this.emit('cache', { | ||
cacheKey: cacheKey, | ||
cacheValue: cacheValue, | ||
response: fetchResponse, | ||
}); | ||
return cacheValue; | ||
}); | ||
}); | ||
if (!_this.operations[cacheKey]) _this.operations[cacheKey] = []; | ||
return cacheValue; | ||
}); | ||
_this.operations[cacheKey] = cacheValuePromise; | ||
_this.operations[cacheKey].push(cacheValuePromise); | ||
resolveOperationsUpdated(); | ||
_this.emit('fetch', { | ||
@@ -106,32 +155,10 @@ cacheKey: cacheKey, | ||
return cacheValuePromise; | ||
}; | ||
this.operate = function (_ref6) { | ||
var operation = _ref6.operation, | ||
fetchOptionsOverride = _ref6.fetchOptionsOverride, | ||
_ref6$cacheKeyCreator = _ref6.cacheKeyCreator, | ||
cacheKeyCreator = | ||
_ref6$cacheKeyCreator === void 0 ? hashObject : _ref6$cacheKeyCreator, | ||
reloadOnLoad = _ref6.reloadOnLoad, | ||
resetOnLoad = _ref6.resetOnLoad; | ||
if (typeof cacheKeyCreator !== 'function') | ||
throw new TypeError( | ||
'operate() option “cacheKeyCreator” must be a function.' | ||
); | ||
if (reloadOnLoad && resetOnLoad) | ||
throw new TypeError( | ||
'operate() options “reloadOnLoad” and “resetOnLoad” can’t both be true.' | ||
); | ||
var fetchOptions = graphqlFetchOptions(operation); | ||
if (fetchOptionsOverride) fetchOptionsOverride(fetchOptions); | ||
var cacheKey = cacheKeyCreator(fetchOptions); | ||
var cacheValuePromise = | ||
_this.operations[cacheKey] || _this.fetch(fetchOptions, cacheKey); | ||
cacheValuePromise.then(function () { | ||
if (reloadOnLoad) _this.reload(cacheKey); | ||
else if (resetOnLoad) _this.reset(cacheKey); | ||
}); | ||
if (reloadOnLoad) | ||
cacheValuePromise.then(function () { | ||
_this.reload(cacheKey); | ||
}); | ||
else if (resetOnLoad) | ||
cacheValuePromise.then(function () { | ||
_this.reset(cacheKey); | ||
}); | ||
return { | ||
@@ -138,0 +165,0 @@ cacheKey: cacheKey, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
97591
17
557
1054