├── README.md ├── header.jpg ├── main.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # GraphQL Suspense 2 | 3 | Easily add suspense to your GraphQL app. 4 | 5 | > Warning, the [React docs](https://reactjs.org/docs/react-api.html#reactsuspense) say that Suspense does not yet support data loading, so in the future there may be breaking changes & better options available. This is experimental, feel free to send prs for improvements. 6 | 7 | ![](header.jpg) 8 | 9 | ## Install 10 | 11 | ```sh 12 | yarn add graphql-suspense 13 | 14 | # or 15 | 16 | npm install graphql-suspense 17 | ``` 18 | 19 | ## Usage ([Apollo](https://www.apollographql.com/docs/react/)) 20 | 21 | ```js 22 | import React, { Component, Suspense } from 'react' 23 | import gqlsuspense from 'graphql-suspense' 24 | 25 | // Define Apollo client 26 | const client = new ApolloClient({ 27 | uri: "" 28 | }) 29 | 30 | class Data extends React.Component { 31 | render() { 32 | const data = gqlsuspense(client.query, { query: listTodos }) 33 | return data.data.listTodos.items.map((t, i) =>

Yo! {t.name}

) 34 | } 35 | } 36 | 37 | const App = () => ( 38 | loading...}> 39 | 40 | 41 | ) 42 | ``` 43 | 44 | ## Usage ([AWS Amplify](https://aws-amplify.github.io/)) 45 | 46 | ```js 47 | import React, { Component, Suspense } from 'react' 48 | import gqlsuspense from 'graphql-suspense' 49 | import { API, graphqlOperation } from 'aws-amplify' 50 | 51 | class Data extends React.Component { 52 | render() { 53 | const data = gqlsuspense(API.graphql(graphqlOperation(listTodos))) 54 | return data.data.listTodos.items.map((t, i) =>

Yo! {t.name}

) 55 | } 56 | } 57 | 58 | const App = () => ( 59 | loading...}> 60 | 61 | 62 | ) 63 | ``` 64 | -------------------------------------------------------------------------------- /header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dabit3/graphql-suspense/03d1203e5d8f36ada29563e5aca2b5f4d5f143ab/header.jpg -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const deepEqual = require('deep-equal'); 2 | 3 | const fetchCaches = [] 4 | 5 | const gqlsuspense = (client, input, variables) => { 6 | const sInput = JSON.stringify(input) 7 | const sVars = JSON.stringify(variables) 8 | for (const fetchCache of fetchCaches) { 9 | if ( 10 | deepEqual(sInput, fetchCache.sInput) && 11 | deepEqual(sVars, fetchCache.sVars) 12 | ) { 13 | 14 | // If an error occurred, 15 | if (Object.prototype.hasOwnProperty.call(fetchCache, 'error')) { 16 | throw fetchCache.error; 17 | } 18 | 19 | // If a response was successful, 20 | if (Object.prototype.hasOwnProperty.call(fetchCache, 'response')) { 21 | return fetchCache.response; 22 | } 23 | throw fetchCache.fetch; 24 | } 25 | } 26 | let fetchCache = { 27 | sVars, 28 | sInput 29 | } 30 | // if there is no input, the client becomes the entire operation 31 | if (!sInput) { 32 | fetchCache = { 33 | ...fetchCache, 34 | fetch: 35 | client 36 | .then(response => { 37 | return response 38 | }) 39 | .then(response => { 40 | fetchCache.response = response; 41 | }) 42 | .catch(e => { 43 | fetchCache.error = e; 44 | }) 45 | } 46 | } else { 47 | // if there is some input, we create an operation 48 | const operation = { 49 | ...input, 50 | variables: { 51 | ...variables 52 | } 53 | } 54 | fetchCache = { 55 | ...fetchCache, 56 | fetch: 57 | client(operation) 58 | .then(response => { 59 | return response 60 | }) 61 | .then(response => { 62 | fetchCache.response = response; 63 | }) 64 | .catch(e => { 65 | fetchCache.error = e; 66 | }) 67 | } 68 | } 69 | fetchCaches.push(fetchCache); 70 | throw fetchCache.fetch; 71 | } 72 | 73 | export default gqlsuspense -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-suspense", 3 | "version": "0.0.7", 4 | "description": "", 5 | "main": "main.js", 6 | "dependencies": { 7 | "deep-equal": "^1.0.1" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "author": "", 13 | "license": "ISC" 14 | } 15 | --------------------------------------------------------------------------------