graphql-react
Advanced tools
Comparing version 2.0.1 to 3.0.0
# graphql-react changelog | ||
## 3.0.0 | ||
### Major | ||
- The `Query` (and the internal `GraphQLQuery`) component take an `operation` prop instead of separate `variables` and `query` props. This makes the implementation a little more elegant, is more consistent with the `GraphQL.query` API and allows sending custom GraphQL operation fields. | ||
- New internal event system, fixing [#10](https://github.com/jaydenseric/graphql-react/issues/10). Now the `loading` parameter of `Query` component render functions change when identical requests are loaded elsewhere in the app. | ||
### Minor | ||
- Improved `Provider` and `Consumer` component display names in React dev tools: | ||
- `Context.Provider` → `GraphQLContext.Provider` | ||
- `Context.Consumer` → `GraphQLContext.Consumer` | ||
### Patch | ||
- Updated dependencies. | ||
- Updated package scripts and config for the new [`husky`](https://npm.im/husky) version. | ||
- Removed the package `module` field. Webpack by default resolves extensionless paths the same way Node.js in `--experimental-modules` mode does; `.mjs` files are preferred. Tools misconfigured or unable to resolve `.mjs` can get confused when `module` points to an `.mjs` ESM file and they attempt to resolve named imports from `.js` CJS files. | ||
- Renamed the `Operation` type `GraphQLOperation`. | ||
- Use [jsDelivr](https://jsdelivr.com) for the readme logo instead of [RawGit](https://rawgit.com) as they are shutting down. | ||
## 2.0.1 | ||
@@ -4,0 +25,0 @@ |
@@ -18,4 +18,6 @@ 'use strict' | ||
const { Provider, Consumer } = _react.default.createContext() | ||
const GraphQLContext = _react.default.createContext() | ||
GraphQLContext.displayName = 'GraphQLContext' | ||
const { Provider, Consumer } = GraphQLContext | ||
exports.Consumer = Consumer | ||
@@ -28,45 +30,37 @@ exports.Provider = Provider | ||
this.handleCacheUpdate = requestCache => { | ||
if (!requestCache && this.props.loadOnReset) this.load() | ||
else | ||
this.onFetch = ({ fetchOptionsHash }) => { | ||
if (fetchOptionsHash === this.state.fetchOptionsHash) | ||
this.setState({ | ||
requestCache | ||
loading: true | ||
}) | ||
} | ||
this.operation = () => ({ | ||
variables: this.props.variables, | ||
query: this.props.query | ||
}) | ||
this.onCache = ({ fetchOptionsHash }) => { | ||
if (fetchOptionsHash === this.state.fetchOptionsHash) | ||
this.setState({ | ||
loading: false, | ||
requestCache: this.props.graphql.cache[fetchOptionsHash] | ||
}) | ||
} | ||
this.onReset = ({ exceptFetchOptionsHash }) => { | ||
if (exceptFetchOptionsHash !== this.state.fetchOptionsHash) | ||
if (this.props.loadOnReset) this.load() | ||
else | ||
this.setState({ | ||
requestCache: null | ||
}) | ||
} | ||
this.load = () => { | ||
const stateUpdate = { | ||
loading: true | ||
} | ||
const { fetchOptionsHash, cache, request } = this.props.graphql.query({ | ||
operation: this.operation(), | ||
operation: this.props.operation, | ||
fetchOptionsOverride: this.props.fetchOptionsOverride, | ||
resetOnLoad: this.props.resetOnLoad | ||
}) | ||
if (fetchOptionsHash !== this.state.fetchOptionsHash) { | ||
stateUpdate.fetchOptionsHash = fetchOptionsHash | ||
this.props.graphql.offCacheUpdate( | ||
this.state.fetchOptionsHash, | ||
this.handleCacheUpdate | ||
) | ||
this.props.graphql.onCacheUpdate( | ||
fetchOptionsHash, | ||
this.handleCacheUpdate | ||
) | ||
} | ||
if (cache) stateUpdate.requestCache = cache | ||
this.setState(stateUpdate, () => | ||
request.then(() => | ||
this.setState({ | ||
loading: false | ||
}) | ||
) | ||
) | ||
this.setState({ | ||
loading: true, | ||
fetchOptionsHash, | ||
cache | ||
}) | ||
return request | ||
@@ -81,3 +75,3 @@ } | ||
const fetchOptions = props.graphql.constructor.fetchOptions( | ||
this.operation() | ||
props.operation | ||
) | ||
@@ -89,7 +83,7 @@ if (props.fetchOptionsOverride) props.fetchOptionsOverride(fetchOptions) | ||
this.state.requestCache = props.graphql.cache[this.state.fetchOptionsHash] | ||
this.props.graphql.onCacheUpdate( | ||
this.state.fetchOptionsHash, | ||
this.handleCacheUpdate | ||
) | ||
} | ||
this.props.graphql.on('fetch', this.onFetch) | ||
this.props.graphql.on('cache', this.onCache) | ||
this.props.graphql.on('reset', this.onReset) | ||
} | ||
@@ -101,18 +95,16 @@ | ||
componentDidUpdate({ query, variables }) { | ||
if ( | ||
this.props.loadOnReset && | ||
this.state.fetchOptionsHash && | ||
(query !== this.props.query || | ||
!(0, _fastDeepEqual.default)(variables, this.props.variables)) | ||
) | ||
this.load() | ||
componentDidUpdate({ operation }) { | ||
if (!(0, _fastDeepEqual.default)(operation, this.props.operation)) | ||
if (this.props.loadOnMount) this.load() | ||
else | ||
this.setState({ | ||
fetchOptionsHash: null, | ||
requestCache: null | ||
}) | ||
} | ||
componentWillUnmount() { | ||
if (this.state.fetchOptionsHash) | ||
this.props.graphql.offCacheUpdate( | ||
this.state.fetchOptionsHash, | ||
this.handleCacheUpdate | ||
) | ||
this.props.graphql.off('fetch', this.onFetch) | ||
this.props.graphql.off('cache', this.onCache) | ||
this.props.graphql.off('reset', this.onReset) | ||
} | ||
@@ -136,4 +128,3 @@ | ||
fetchOptionsOverride: _propTypes.default.func, | ||
variables: _propTypes.default.object, | ||
query: _propTypes.default.string.isRequired, | ||
operation: _propTypes.default.object.isRequired, | ||
loadOnMount: _propTypes.default.bool, | ||
@@ -161,4 +152,3 @@ loadOnReset: _propTypes.default.bool, | ||
fetchOptionsOverride: _propTypes.default.func, | ||
variables: _propTypes.default.object, | ||
query: _propTypes.default.string.isRequired, | ||
operation: _propTypes.default.object.isRequired, | ||
loadOnMount: _propTypes.default.bool, | ||
@@ -165,0 +155,0 @@ loadOnReset: _propTypes.default.bool, |
@@ -12,34 +12,44 @@ 'use strict' | ||
var _extractFiles = require('extract-files') | ||
var _fnv1a = _interopRequireDefault(require('fnv1a')) | ||
var _extractFiles = require('extract-files') | ||
var _mitt = _interopRequireDefault(require('mitt')) | ||
class GraphQL { | ||
constructor({ cache = {} } = {}) { | ||
this.requests = {} | ||
this.listeners = {} | ||
static requestBody(operation) { | ||
const files = (0, _extractFiles.extractFiles)(operation) | ||
this.onCacheUpdate = (fetchOptionsHash, callback) => { | ||
if (!this.listeners[fetchOptionsHash]) | ||
this.listeners[fetchOptionsHash] = [] | ||
this.listeners[fetchOptionsHash].push(callback) | ||
} | ||
if (files.length) { | ||
const form = new FormData() | ||
form.append('operations', JSON.stringify(operation)) | ||
form.append( | ||
'map', | ||
JSON.stringify( | ||
files.reduce((map, { path }, index) => { | ||
map[`${index}`] = [path] | ||
return map | ||
}, {}) | ||
) | ||
) | ||
files.forEach(({ file }, index) => form.append(index, file, file.name)) | ||
return form | ||
} else return JSON.stringify(operation) | ||
} | ||
this.offCacheUpdate = (fetchOptionsHash, callback) => { | ||
if (this.listeners[fetchOptionsHash]) { | ||
this.listeners[fetchOptionsHash] = this.listeners[ | ||
fetchOptionsHash | ||
].filter(listenerCallback => listenerCallback !== callback) | ||
if (!this.listeners[fetchOptionsHash].length) | ||
delete this.listeners[fetchOptionsHash] | ||
static fetchOptions(operation) { | ||
const fetchOptions = { | ||
url: '/graphql', | ||
method: 'POST', | ||
headers: { | ||
Accept: 'application/json' | ||
} | ||
} | ||
fetchOptions.body = this.requestBody(operation) | ||
if (typeof fetchOptions.body === 'string') | ||
fetchOptions.headers['Content-Type'] = 'application/json' | ||
return fetchOptions | ||
} | ||
this.emitCacheUpdate = (fetchOptionsHash, requestCache) => { | ||
if (this.listeners[fetchOptionsHash]) | ||
this.listeners[fetchOptionsHash].forEach(callback => | ||
callback(requestCache) | ||
) | ||
} | ||
constructor({ cache = {} } = {}) { | ||
this.reset = exceptFetchOptionsHash => { | ||
@@ -54,5 +64,5 @@ let fetchOptionsHashes = Object.keys(this.cache) | ||
) | ||
fetchOptionsHashes.forEach(fetchOptionsHash => | ||
this.emitCacheUpdate(fetchOptionsHash) | ||
) | ||
this.emit('reset', { | ||
exceptFetchOptionsHash | ||
}) | ||
} | ||
@@ -71,2 +81,5 @@ | ||
) | ||
this.emit('fetch', { | ||
fetchOptionsHash | ||
}) | ||
return (this.requests[fetchOptionsHash] = fetcher(url, options)) | ||
@@ -98,4 +111,6 @@ .then( | ||
this.cache[fetchOptionsHash] = requestCache | ||
this.emitCacheUpdate(fetchOptionsHash, requestCache) | ||
delete this.requests[fetchOptionsHash] | ||
this.emit('cache', { | ||
fetchOptionsHash | ||
}) | ||
return requestCache | ||
@@ -121,37 +136,8 @@ }) | ||
this.cache = cache | ||
this.requests = {} | ||
const { on, off, emit } = (0, _mitt.default)() | ||
this.on = on | ||
this.off = off | ||
this.emit = emit | ||
} | ||
static requestBody(operation) { | ||
const files = (0, _extractFiles.extractFiles)(operation) | ||
if (files.length) { | ||
const form = new FormData() | ||
form.append('operations', JSON.stringify(operation)) | ||
form.append( | ||
'map', | ||
JSON.stringify( | ||
files.reduce((map, { path }, index) => { | ||
map[`${index}`] = [path] | ||
return map | ||
}, {}) | ||
) | ||
) | ||
files.forEach(({ file }, index) => form.append(index, file, file.name)) | ||
return form | ||
} else return JSON.stringify(operation) | ||
} | ||
static fetchOptions(operation) { | ||
const fetchOptions = { | ||
url: '/graphql', | ||
method: 'POST', | ||
headers: { | ||
Accept: 'application/json' | ||
} | ||
} | ||
fetchOptions.body = this.requestBody(operation) | ||
if (typeof fetchOptions.body === 'string') | ||
fetchOptions.headers['Content-Type'] = 'application/json' | ||
return fetchOptions | ||
} | ||
} | ||
@@ -158,0 +144,0 @@ |
{ | ||
"name": "graphql-react", | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"description": "A lightweight GraphQL client for React.", | ||
@@ -31,3 +31,2 @@ "license": "MIT", | ||
"main": "lib", | ||
"module": "lib/index.mjs", | ||
"sideEffects": false, | ||
@@ -42,6 +41,7 @@ "engines": { | ||
"dependencies": { | ||
"@babel/runtime": "^7.0.0", | ||
"@babel/runtime": "^7.1.2", | ||
"extract-files": "^4.0.0", | ||
"fast-deep-equal": "^2.0.1", | ||
"fnv1a": "^1.0.1", | ||
"mitt": "^1.1.3", | ||
"object-assign": "^4.1.1", | ||
@@ -51,4 +51,4 @@ "prop-types": "^15.6.1" | ||
"devDependencies": { | ||
"@babel/cli": "^7.1.0", | ||
"@babel/core": "^7.1.0", | ||
"@babel/cli": "^7.1.2", | ||
"@babel/core": "^7.1.2", | ||
"@babel/plugin-proposal-class-properties": "^7.1.0", | ||
@@ -59,6 +59,6 @@ "@babel/plugin-proposal-object-rest-spread": "^7.0.0", | ||
"@babel/preset-react": "^7.0.0", | ||
"babel-eslint": "^10.0.0", | ||
"babel-eslint": "^10.0.1", | ||
"babel-plugin-transform-replace-object-assign": "^2.0.0", | ||
"cross-fetch": "^2.2.2", | ||
"eslint": "^5.6.0", | ||
"eslint": "^5.7.0", | ||
"eslint-config-env": "^1.1.0", | ||
@@ -68,7 +68,7 @@ "eslint-config-prettier": "^3.1.0", | ||
"eslint-plugin-node": "^7.0.1", | ||
"eslint-plugin-prettier": "^2.6.2", | ||
"eslint-plugin-prettier": "^3.0.0", | ||
"eslint-plugin-react": "^7.11.1", | ||
"graphql": "^14.0.2", | ||
"graphql-api-koa": "^1.1.0", | ||
"husky": "^1.0.0", | ||
"graphql-api-koa": "^2.0.0", | ||
"husky": "^1.1.2", | ||
"jsdoc-md": "^1.6.0", | ||
@@ -81,3 +81,3 @@ "koa": "^2.5.3", | ||
"react-dom": "^16.5.2", | ||
"size-limit": "^0.20.0", | ||
"size-limit": "^0.20.1", | ||
"tap": "^12.0.1", | ||
@@ -100,5 +100,9 @@ "watch": "^1.0.2" | ||
"prepublishOnly": "npm run prepare && npm test", | ||
"watch": "watch 'npm run prepublishOnly --silent' src --interval 1", | ||
"precommit": "lint-staged" | ||
"watch": "watch 'npm run prepublishOnly --silent' src --interval 1" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
@@ -105,0 +109,0 @@ "*.{mjs,js}": "eslint", |
@@ -1,2 +0,2 @@ | ||
![graphql-react logo](https://cdn.rawgit.com/jaydenseric/graphql-react/b2e60e80/graphql-react-logo.svg) | ||
![graphql-react logo](https://cdn.jsdelivr.net/gh/jaydenseric/graphql-react@0.1.0/graphql-react-logo.svg) | ||
@@ -72,5 +72,5 @@ # graphql-react | ||
}} | ||
variables={{ name }} | ||
query={ | ||
/* GraphQL */ ` | ||
operation={{ | ||
variables: { name }, | ||
query: /* GraphQL */ ` | ||
query pokemon($name: String!) { | ||
@@ -83,3 +83,3 @@ pokemon(name: $name) { | ||
` | ||
} | ||
}} | ||
> | ||
@@ -145,4 +145,4 @@ {({ loading, data }) => | ||
- [Examples](#examples-8) | ||
- [type GraphQLOperation](#type-graphqloperation) | ||
- [type HttpError](#type-httperror) | ||
- [type Operation](#type-operation) | ||
- [type QueryRender](#type-queryrender) | ||
@@ -178,3 +178,3 @@ - [Examples](#examples-9) | ||
| `options` | [Object](https://mdn.io/object) | Options. | | ||
| `options.operation` | [Operation](#type-operation) | GraphQL operation object. | | ||
| `options.operation` | [GraphQLOperation](#type-graphqloperation) | GraphQL operation. | | ||
| `options.fetchOptionsOverride` | [FetchOptionsOverride](#type-fetchoptionsoverride)? | Overrides default GraphQL request [fetch options](#type-fetchoptions). | | ||
@@ -189,5 +189,5 @@ | `options.resetOnLoad` | [boolean](https://mdn.io/boolean)? = `false` | Should the [GraphQL cache](#graphql-instance-property-cache) reset when the query loads. | | ||
| Parameter | Type | Description | | ||
| :----------------------- | :------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `exceptFetchOptionsHash` | [string](https://mdn.io/string)? | A [fetch options](#type-fetchoptions) hash to exempt a request from cache deletion. Useful for resetting cache after a mutation, preserving the mutation cache. | | ||
| Parameter | Type | Description | | ||
| :----------------------- | :------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `exceptFetchOptionsHash` | [string](https://mdn.io/string)? | A [fetch options](#type-fetchoptions) hash for cache to exempt from deletion. Useful for resetting cache after a mutation, preserving the mutation cache. | | ||
@@ -305,4 +305,3 @@ ##### Examples | ||
| `props` | [Object](https://mdn.io/object) | Component props. | | ||
| `props.variables` | [Object](https://mdn.io/object)? | GraphQL query variables. | | ||
| `props.query` | [string](https://mdn.io/string) | GraphQL query. | | ||
| `props.operation` | [GraphQLOperation](#type-graphqloperation) | GraphQL operation. | | ||
| `props.fetchOptionsOverride` | [FetchOptionsOverride](#type-fetchoptionsoverride)? | Overrides default GraphQL request [fetch options](#type-fetchoptions). | | ||
@@ -328,12 +327,14 @@ | `props.loadOnMount` | [boolean](https://mdn.io/boolean)? = `false` | Should the query load when the component mounts. | | ||
> fetchOptionsOverride={options => { | ||
> options.url = 'https://api.example.com/graphql' | ||
> options.url = 'https://api.example.com/graphql' | ||
> }} | ||
> variables={{ userId }} | ||
> query={` | ||
> query user($userId: ID!) { | ||
> user(userId: $userId) { | ||
> name | ||
> operation={ | ||
> variables: { userId }, | ||
> query: ` | ||
> query user($userId: ID!) { | ||
> user(userId: $userId) { | ||
> name | ||
> } | ||
> } | ||
> } | ||
> `} | ||
> ` | ||
> } | ||
> > | ||
@@ -373,10 +374,12 @@ > {({ | ||
> }} | ||
> variables={{ articleId }} | ||
> query={` | ||
> mutation clapArticle($articleId: ID!) { | ||
> clapArticle(articleId: $articleId) { | ||
> clapCount | ||
> operation={ | ||
> variables: { articleId }, | ||
> query: ` | ||
> mutation clapArticle($articleId: ID!) { | ||
> clapArticle(articleId: $articleId) { | ||
> clapCount | ||
> } | ||
> } | ||
> } | ||
> `} | ||
> ` | ||
> } | ||
> > | ||
@@ -457,6 +460,6 @@ > {({ | ||
| Parameter | Type | Description | | ||
| :------------- | :--------------------------------- | :------------------------------------- | | ||
| `fetchOptions` | [FetchOptions](#type-fetchoptions) | Default GraphQL request fetch options. | | ||
| `operation` | [Operation](#type-operation)? | A GraphQL operation object. | | ||
| Parameter | Type | Description | | ||
| :------------- | :------------------------------------------ | :------------------------------------- | | ||
| `fetchOptions` | [FetchOptions](#type-fetchoptions) | Default GraphQL request fetch options. | | ||
| `operation` | [GraphQLOperation](#type-graphqloperation)? | GraphQL operation. | | ||
@@ -474,2 +477,13 @@ #### Examples | ||
### type GraphQLOperation | ||
A GraphQL operation. Additional properties may be used; all are sent to the GraphQL server. | ||
**Type:** [Object](https://mdn.io/object) | ||
| Property | Type | Description | | ||
| :---------- | :------------------------------ | :---------------------------- | | ||
| `query` | [string](https://mdn.io/string) | GraphQL queries or mutations. | | ||
| `variables` | [Object](https://mdn.io/object) | Variables used by the query. | | ||
### type HttpError | ||
@@ -486,13 +500,2 @@ | ||
### type Operation | ||
A GraphQL operation object. Additional properties may be used; all are sent to the GraphQL server. | ||
**Type:** [Object](https://mdn.io/object) | ||
| Property | Type | Description | | ||
| :---------- | :------------------------------ | :---------------------------- | | ||
| `query` | [string](https://mdn.io/string) | GraphQL queries or mutations. | | ||
| `variables` | [Object](https://mdn.io/object) | Variables used by the query. | | ||
### type QueryRender | ||
@@ -499,0 +502,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
546
57287
8
660
+ Addedmitt@^1.1.3
+ Addedmitt@1.2.0(transitive)
Updated@babel/runtime@^7.1.2