GithubHelp home page GithubHelp logo

jaydenseric / graphql-react Goto Github PK

View Code? Open in Web Editor NEW
715.0 12.0 27.0 1.25 MB

A GraphQL client for React using modern context and hooks APIs that is lightweight (< 4 kB) but powerful; the first Relay and Apollo alternative with server side rendering.

Home Page: https://npm.im/graphql-react

License: MIT License

JavaScript 100.00%
graphql react mjs node hooks esm maintained npm deno typescript

graphql-react's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql-react's Issues

Add ability to load on mount only if no cache

Hi Jayden,
First, thanks for the great work on the lib!

I was wondering if there is a way to cache a query, even when after unmounting:
So for example I have a query being triggered when my page mounts, if I navigate out and just hit browser back button, the query is triggered again.
In that case I would like the cache to take over instead of refetching the content.

Is that something that could be easily implemented?

Thanks!

Edit: related to this but not entirely, I think it would be great to be able to customize firstRenderDate timeout, right now it's hardcoded do 1000ms but I had a case where I had a rerender happening after 1s and it was triggering an unecessary refetch.
Being able to force the cache to be used per hook would solve this issue as well!

Document the `load` function

Hi,
First of all, thanks for this great library. Using it on my latest project and it's been great so far.

I'm currently building a "search" functionality that naturally requires imperative graphQL query to be achieved: user fills an input then the fetch is triggered.
I found the load method that's returned from useGraphQL in the issues. Is that undocumented on purpose? Or is it just missing?

Would you accept a PR for this? It could come along with a code example.

Thanks!

How to move gql query to useGraphQL operation query

I want to move my gql query to useGraphQL query.I am getting errors.i do not want to use gql now.


`USER_QUERY = gql`
  query Plan($_id: String!) {
     user(_id: $_id) {
        language
        profile {
        emailAddress
      }
      travelPolicy {
        budgetPlan {
          plan {
            allowBooking
          }
        }
      }
    }
  }
`;`

  const { loading, cacheValue = {} } = useGraphQL({
     fetchOptionsOverride(options) {
      options.url = "http://localhost:3030/graphql";
    },
    operation: {
      query: `
     Plan($_id: String!) {
     user(_id: $_id) {
        language
        profile {
        emailAddress
      }
      travelPolicy {
        budgetPlan {
          plan {
            allowBooking
          }
        }
      }
    }
  }
      `,
    },
    loadOnMount: true,
    loadOnReload: true,
    loadOnReset: true,
  });

How to use useGraphQL hooks when handleLoadMore functions trigger?

I am trying to implement scroll pagination. For this on handleLoadMore, I want to fire graphql query and with new data want to update my state.

This code is not working for me :-

getting error
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of
the following reasons:

const handleLoadMore = () => {
  setLoading(true);
  const { loading, cacheValue = {} } = useGraphQL({
    fetchOptionsOverride(options) {
      options.url = GRAPHQL_URL;
    },
    operation: {
      query: SEARCH_PROPERTYGROUPS_QUERY,
      variables: { ...queryVariables },
    },
    loadOnMount: true,
    loadOnReload: true,
    loadOnReset: true,
  }); 
  
 setItems([...items, newPage.items]); // Want to update my state with cacheValue data

};

Does this work out of the box with ApolloServer?

Hey, this looks great, thanks so much for making this available! I like how light and clear the API is and I like that it doesn't use TS. :-)

I'm currently using ApolloClient and ApolloServer (via apollo-server-express). ApolloServer seems to work really well but ApolloClient seems to have some serious bugs around caching ...

My Question: If I swap this out for ApolloClient, should graphql-react just work directly with ApolloServer without any server changes needed?

I ask because Relay seems to need a "RelayServer" so I'm avoiding that. I'd like to use graphql-react talking to ApolloServer and I'm not sure if that would work directly?

Sorry for filing this as an issue, I just wasn't sure how to ask this question otherwise (if there's a better way, please let me know) ...

Thanks again for all of your hard work on this! :-)

P.S. I will need to use this in ReactNative as well - do you see any reason why it wouldn't also work in RN? Thanks.

TypeScript support

I am curious if it's planned? From my experience, it is so much easier to have a project written in Typescript instead of creating ad-hoc typings and maintaining those (same way as react-apollo does it).

It's not a problem to use .mjs, the TypeScript is able to emit full ESM module, although it will be with .js extension so there would need to be an extra step of renaming those, but that should be easy.

Investigate useMemo for useGraphQL hook

With the pre-hooks Query component API:

  • Hashing of the fetch options didn't happen every render.
  • Deep changes in the GraphQL operations object would trigger a reload (if loadOnMount was true). fast-deep-equal was used here.

I suspect the useMemo React hook could be used someone to add those smarts to the new useGraphQL API.

graphql-react example script not working.

The example script fails.

git clone https://github.com/jaydenseric/graphql-react.git && cd graphql-react/example && npm install && npm run dev

Returns:

TypeError: Object(...) is not a function

Support subscriptions

Great library, and mostly fits my design goals. Really like the hash-based cache choice, easiness of having non-singleton configuration, and most of all library size.

I was wondering if you have given any further thought to subscriptions. This is something I would like to have, and am thinking around writing an integration when the time comes. You know the GraphQL ecosystem better than I, and so was wondering if you had any thoughts.

Thanks!

edit: One simple way of doing this would be to rely on prop-mutation-based refetch (send a simple websocket notification with say a hash of the query, mutate a prop, and cause graphql-react to refetch), but that seems mostly wasteful. I want to be able to send a diff, and reconcile with the data already stored in grahpql-react. It's certainly possible to do this completely outside the graphql ecosystem, which is what I have previously implemented (a bit like graphql, in that I send a json object containing the dag representing the diff, and reconcile that dag with the client-stored stale data, by walking the shared portions of these two graphs and updating the leaves on the client store).

Cancel in-flight requests when they are invalidated

When an in-progress query is invalidated (due to variables changing, or the react component being removed from the virtual DOM, etc) we need to cancel the request and open up space in the browser's request queue.

For me, this is especially important in a "search-while-typing" interface, where in-flight queries are frequently invalidated by more user input.

SSR on PHPv8js

Your library is the one I have been looking for months! I just cannot afford big bundle sizes in my web app!

Is there any way to run this as a normal sync function?

let str = ssr(graphql, page);

This is to make SSR easier with php-v8js

Publish the GraphQL client in a separate package

Hello Jayden

Thank you for this great module. I just switch from Apollo-client to graphQL-react and it feels much better!

I am using graphQl-react in a non-react app. Currently, I have to install react and react-dom to use it.
Would you consider extracting the GraphQL class in a separate npm module with no dependencies on react?

Thank you


Also, here is an example code of the GraphQL client running in node.
This could be helpful to have this example in the docs,
at least for me :-).

const fetch = require('node-fetch')
const { GraphQL } = require('graphql-react')
const graphql = new GraphQL()

if (!globalThis.fetch) {
  globalThis.fetch = fetch
}

const apiFetch = query => async variables => {
  try {
    const res = await graphql.operate({
      operation: { query, variables },
      fetchOptionsOverride: options => {
        options.url = 'https://graphql-pokemon.now.sh'
      }
    })

    const value = await res.cacheValuePromise

    if (value.graphQLErrors) throw value.graphQLErrors[0]
    if (value.fetchError) throw value.fetchError
    if (value.httpError) throw value.httpError
    if (value.parseError) throw value.parseError

    return value.data
  } catch (e) {
    const errorMessage = `Erreur API : ${e.message}`
    console.error(e)
    throw errorMessage
  }
}

const pokemon = apiFetch(
  'query Pokemon($name: String!) { pokemon(name: $name) { image } }'
)

const run = async () => {
  const res = await pokemon({ name: 'pikachu' })

  console.log(res)
}

run()

Implementing with-graphql-react example alongside createGlobalstyle from styled-components causes conflicts

Hello,

Just today I found this behavior and would like to start a discussion in order to get to the bottom of it, because really, I'm not sure how to fix it.

This is the error:

(node:22363) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'children' of undefined
    at GlobalStyleComponent.render (/Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/styled-components/dist/styled-co
mponents.cjs.js:2376:93)
    at recurse (/Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:104:35)
    at /Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:40:20
    at Array.forEach (<anonymous>)
    at recurse (/Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:39:19)
    at recurse (/Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:112:11)
    at recurse (/Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:104:18)
    at recurse (/Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:104:18)
    at recursePreload (/Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:116:7)
    at /Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:120:5
    at new Promise (<anonymous>)
    at preload (/Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/graphql-react/lib/preload.js:14:10)
    at /Users/Felipe/Local_Projects/wagglio-gitlab/monorepo/node_modules/next-graphql-react/lib/index.js:77:38
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:22363) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:22363) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

It seems like a conflict between preload and createGlobalStyles (from styled-components). This is the implementation of global styles, it goes according to their docs:

import { normalize } from 'styled-normalize'
import { createGlobalStyle } from 'styled-components'

import { scales } from './variables'

export const WGlobalStyles = createGlobalStyle`
  ${normalize}
  html {
  font-size: ${scales.baseFont}px;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;

  }
  *, *:before, *:after {
    -webkit-box-sizing: inherit;
    -moz-box-sizing: inherit;
    box-sizing: inherit;
  }
`

It's simply the implementation of base font sizes and resets from styled-normalize and just a bit of my own.

This is the _app.js implementation on the side of Next.js. Comes directly from the example with-graphql-react and trying to implement the global styles :

import 'cross-fetch/polyfill'
import {Provider} from 'graphql-react'
import {withGraphQL} from 'next-graphql-react'
import App, { Container } from 'next/app'

import { WGlobalStyles } from '@wagglio/components'

class WagglioMainApp extends App {
    render() {
    const { Component, pageProps, graphql } = this.props
    return (
      <Container>
        <Provider value={graphql}>
          <WGlobalStyles />
          <Component {...pageProps} />
        </Provider>
      </Container>
    )
  }
}

export default withGraphQL(WagglioMainApp)

Everything works whenever I comment out <WGlobalStyles />. Not sure how to pin point the unhandled promise in this case.

If there's any other info I can provide in order to help solve this, please let me know.

Cheers

Mutation example

hi, i struggled a little bit with the mutations.
at last i made it work. If someone has the same question here is a short example:

import {Query} from "graphql-react/lib/components";

export default () => (
    <Query
        loadOnMount
        loadOnReset
        fetchOptionsOverride={options => {
            options.url = 'http://localhost:8080/query'
        }}
        operation={{
            query: /* GraphQL */ `
              mutation {
                createAddition(input: { number: 22, anotherNumber: 33 }) {
                  result
                }
              }
            `
        }}
    >
        {({ data, loading }) =>
            data ? (
                <div>{data.createAddition.result}</div>
            ) : loading ? (
                <p>Loading…</p>
            ) : (
                <p>Error!</p>
            )
        }
    </Query>
)

@jaydenseric maybe you can use it for the docs

Possibly missing files within package

If we look at the official NextJS example, under examples/with-graphql-react/next.config.js- the following package is required: const { withGraphQLConfig } = require('next-graphql-react/server')

When installing next-graphql-react now the 'server' path is missing. If things have changed in the latest versions please update example.

Thanks

Usage with class components?

There's an example in the docs showing the use of the Query component, but it no longer works. I'm assuming I use GraphQLContext.Consumer instead, but is there an example of usage with this? (I'm getting an infinite loop if I do graphql.operate() call in render()).

Make readme a bit more friendly for new users

Hey, 👋

I'm finally trying this package (with hooks) instead of apollo mess and have some suggestions:

The biggest one is lack of examples - using Api section to gather pieces of examples in a whole picture is pretty hard for a new user and examples section suggests visiting another repos with next.js examples which also doesn't really help in a plain koa + graphql-api-koa project.

Some examples in the docs, before Api section - not codesandbox or other repo links, just some plain md examples with basic things - set up provider, write a query, run a query, run a mutation. They would really help.

Second suggestion is to move apollo comparison to bottom maybe - it's kinda big and you have to scroll a lot to get to setup/usage sections and is not needed for people, who don't use apollo or just want to quick start with this package.

Thanks and sorry for the issues, just sharing my thoughts from a new user perspective. As an author, it's sometimes not obvious to see this because you are familiar with the package. I think this changes may help new users a lot :)

Add a license file

Without a license anyone who uses this library is infringing your copyright. Do you plan to open source the code? Have I missed the licensing blurb? Without it you might find adoption is limited. Thanks.

Examples of SSR cache hydration

I'm hydrating the cache in the client browser as follows:

const graphqlClient = new GraphQL({ cache:  window.__GRAPHQL_STATE__ })

window.__GRAPHQL_STATE__ is an object like this:

{
  '18s6t0k': {
    'data': ...
  }
}

However I'm still seeing the graphql requests hitting the graphql server two times, once on server load and once on client. I've tried disabling the call on client/server code each independently and can confirm it's not simply just running two times.

Add a server side rendering API

  • Export a server function for rendering a component tree to cache.
  • Cache can be used for a network request free server side render.
  • Cache can be hydrated on the client for an initial render.
  • Update the Next.js example to SSR.

Weird query lifecycle transitions

Hey there! I discovered your library yesterday and decided to give it a try because I think its caching mechanism is superior to what graphql-hooks (what I'm currently using) offers.

What I'm doing

To make migration easier, I'm creating the following hook:

import { useGraphQL } from 'graphql-react';

const fetchOptionsOverride = options => {
  options.url = '/api/graphql';
};

const useQuery = (query, { variables } = {}) => {
  const {
    loading,
    cacheValue: { data, fetchError, httpError, parseError, graphQLErrors } = {},
  } = useGraphQL({
    fetchOptionsOverride,
    operation: {
      variables,
      query,
    },
  });

  const error = fetchError || httpError || parseError || graphQLErrors;

  console.log({ loading, error, data }); // <- Remember this call to console.log.

  return {
    loading,
    error,
    data,
  };
};

export default useQuery;

What I expect

Later, in my component I expect to be able to use useQuery like this:

const postQuery = /* GraphQL */ `...`;

const Post = ({ postId }) => {
  const { loading, error, data } = useQuery(postQuery, {
    variables: {
      postId,
    },
  });

  if (loading) {
    return 'Loading...';
  }

  if (error) {
    return 'Something went wrong.';
  }

  return (
    <article>
      <h1>{data.post.title}</h1>
      <p>{data.post.content}</p>
    </article>
  );
};

What actually happens

Blows up when trying to access data.post.title. I traced that down to the different values loading, error and data have during the query lifecycle:

  1. { loading: false, error: undefined, data: undefined }

All three values are falsy at the beginning, thus provoking the issue I just mentioned with my component's code.

  1. { loading: true, error: undefined, data: undefined }

loading is set to true when load() is called inside useGraphQL.

  1. { loading: false, error: undefined, data: undefined }

When that finishes, loading returns to false, but neither error nor data are set (problematic, if you ask me).

  1. { loading: false, error: undefined, data: {…} }

Finally, data is populated with the result of the GraphQL query.

I would expect this sequence to be like this instead:

  1. { loading: true, error: undefined, data: undefined }
  2. { loading: false, error: undefined, data: {…} }

Am I doing something wrong in my useQuery hook? Is this the expected behavior?

Multiple operations on the same query

This is somewhat what I want to achieve

operation: {
      variables: { sanitizedemail },
      query: /* GraphQL */ `
        mutation SubscribeToMarketing($sanitizedemail: String!) {
          mailchimpAddContact(params: { email: $sanitizedemail }) {
            email
          }
        }
        mutation CreateUserOnDb($sanitizedemail: String!) {
          dbCreateUser(params: { email: $sanitizedemail }) {
            email
          }
        }
      `,
    },

What am I missing to make it work with graphql-react?

I'm a little lost on this, any help is appreciated

Cheers

Fix preload SSR API for React v16.6

React v16.6 has some breaking changes to the way the new context API works, causing errors and warnings when attempting to use the preload SSR API, such as:

Warning: Rendering <Context.Consumer.Consumer> is not supported and will be removed in a future major release. Did you mean to render <Context.Consumer> instead?
Warning: Failed prop type: The prop `graphql` is marked as required in `GraphQLQuery`, but its value is `undefined`.
Error: Cannot read property 'constructor' of undefined
      at new GraphQLQuery (file://lib/components.mjs:57:42)

I suspect react-apollo will encounter issues too: apollographql/react-apollo#2530

Suspense mode ?

It would be useful if we could enable suspense:true option , so that the library is compatible with future SSR Suspense release.

Using localhost graphql API results in error 400.

I'm using "with-graphql-react" example from next.js repo. During development, I'm using django backend's graphql api from localhost:8000. However I'm stuck at initial step with error response 400.

My index.js:

import {useGraphQL} from 'graphql-react'

const Index = () => {
const {loading, cacheValue = {}} = useGraphQL({
fetchOptionsOverride(options) {
options.url = 'http://localhost:8000/api/graphql/'
options.mode = 'no-cors'
},
operation: {
query: { allArticles { id } }
}
})

return cacheValue.data ? (
    
    <p>Hello</p>
) : loading ? (
    <p>Loading…</p>
) : (
    <p>Error!</p>
)

}

export default Index

This query is working fine in graphiql, however using this in nextjs results to two following alternating errors below from web inspector:

"message": "Must provide query string."

and

Error response

Error code: 400

Message: Bad request syntax ('{"query":"\n{\n allArticles {\n id\n }\n}\n "}POST /api/graphql/ HTTP/1.1').

Error code explanation: HTTPStatus.BAD_REQUEST - Bad request syntax or unsupported method.

Can anyone point me towards right direction? Thanks.

Passing URL parameters

Unable to get nextjs url parameters (query) on server-side using getInitialProps using the Provider

WITH PROVIDER
image

WITHOUT PROVIDER
image

Default fetch URL

I didn't see this in the docs. Does the fetch URL have to be set as an override for every single query, or is there an option to set a default one when instantiating the client?

Gatsby plugin/example ?

Firstly, thanks you for great work here ! It's such a breath air for a simple design for Graphql !

Secondly, do you have any example/guide on how to use this with Gatsby ?

Pagination possible?

Hello,

I am considering using this package for a decent-sized project. It appears to me that there is no great way to do pagination with this package, is that correct?

Thanks,
Paul

Disable SSR for specific queries

Hey, do you think it could be relevant to add an option to disable a query to run on the server ?

I have a use case where I want the nextjs app to load first, and dont wait for all queries to run.
An option to force some specifically slow queries to run on the client-only could help.

Tell me if it you need more information / an example repo to explain my use case.

Anyone used useGraphQL Mutation in Forms (Formik) ?

My bad if the questions comes off as ignorant. Coming from data engineering background, I'm still a beginner in web development.

I've using UseGraphQL hook to fetch the data successfully and able to display the data on a nextjs ssr website. However when creating a form page with Formik library, I'm stuck at the error message "Hooks can only be called inside the body of a function component." Cannot find any similar examples using form to mutate data using GraphQL hook anywhere.

_app.js File:

import 'cross-fetch/polyfill'
import {GraphQLContext} from 'graphql-react'
import {withGraphQLApp} from 'next-graphql-react'
import App, {Container} from 'next/app'
import Head from 'next/head'

class KSApp extends App {
    render() {
        const {Component, pageProps, graphql} = this.props
        return (
            <Container>
                <Head>
                    <link rel="icon" href="/static/favicon.ico"/>
                </Head>
                <GraphQLContext.Provider value={graphql}>
                        <Component {...pageProps} />
                </GraphQLContext.Provider>

            </Container>
        )
    }
}

export default withGraphQLApp(KSApp)

FormPage File:

import React, {useState} from 'react'
import {Formik} from 'formik'
import {useGraphQL} from 'graphql-react'
import {KSStrapiFetchOptionsOverride} from './data/graphql-fetch-options'

const MutateContact = (values) => {
    useGraphQL({
        fetchOptionsOverride: KSStrapiFetchOptionsOverride,
        operation: {
            query: `
mutation {
  createContact (input: {
    data: {
      feedback: ${values.feedback}
    }
  }
  ) {
  contact {
    feedback
  }
  }
}
`
        }
    })
}

const BasicExample = () => {
    
    return <div>
        <h1>My Form</h1>
        <Formik
            initialValues={{feedback: 'some feedback'}}
            onSubmit={(values, actions) => {
                setTimeout(() => {
                    alert(JSON.stringify(values, null, 2))
                    
                    MutateContact(values)
                    
                    actions.setSubmitting(false)
                }, 1000)
            }}
            render={props => (
                <form onSubmit={props.handleSubmit}>
                    <input
                        type="text"
                        onChange={props.handleChange}
                        onBlur={props.handleBlur}
                        value={props.values.feedback}
                        name="feedback"
                    />
                    {props.errors.feedback && <div id="feedback">{props.errors.feedback}</div>}
                    <button type="submit">Submit</button>
                </form>
            )}
        />
    </div>
}

export default BasicExample

This results to "Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)" error.

You might have mismatching versions of React and React DOM. (Ruled out)
You might be breaking the Rules of Hooks. (Assuming this is causing error)
You might have more than one copy of React in the same app. (Ruled out)

Can anyone point me towards right direction?
Under assumption MutateContact is a function in the above code, so usage of hooks should be okay right?

Support polling?

A more simple method to support somewhat real time data than subscriptions would be a polling mechanism. Is this something you would consider adding?

NODE_ENV=production breaks preload

All the tests pass normally for v4, but one fails when NODE_ENV=production, resulting in the following error:

Cannot read property 'currentValue' of undefined

I found this after deploying graphql-react v4 with graphql-react-examples 😞

Consider adding HOCs

Hey,

I've been looking at this project for a long time with a great desire to try it. I used render props in apollo and it was a horrible experience which I'd never want to have again. Luckily, apollo still has HOCs which are working fine and I'm one of a few happy devs who know they exist.

As I can see, in latest major version (8) hooks is the way to do things. However, I'm a huge fan of HOCs and this is the thing I would love to have before transitioning from apollo.

So my question is - maybe there is a chance to add HOCs support to this great package?

I know, they can be possibly created using current tools, but I'd prefer them built-in to be sure I didn't mess up with something, to know someone else might be using them (possibility to find bugs/ask features) and to have support from the author.

New composable React hooks

Currently, the useGraphQL React hook does a lot, which is not desirable for a few reasons:

  1. It's hard to test. With so many options interacting with each other, every option variation needs to be tested with most of the variations of the other options.

  2. Options have a performance cost regardless if they are being used. For example, the loadOnReset option utilizes a React.useCallback and a React.useEffect:

    /**
    * Handles the [`GraphQL`]{@link GraphQL} [`reset`]{@link GraphQL#event:reset}
    * event.
    * @param {GraphQL#event:reset} event Event data.
    * @ignore
    */
    const onReset = React.useCallback(
    ({ exceptCacheKey }) => {
    if (cacheKey !== exceptCacheKey && isMountedRef.current) {
    ReactDOM.unstable_batchedUpdates(() => {
    setCacheValue(graphql.cache[cacheKey]);
    setLoadedCacheValue(graphql.cache[cacheKey]);
    });
    if (loadOnReset) load();
    }
    },
    [cacheKey, graphql.cache, load, loadOnReset]
    );
    React.useEffect(() => {
    graphql.on('reset', onReset);
    return () => {
    graphql.off('reset', onReset);
    };
    }, [graphql, onReset]);

  3. The code supporting options increases the bundle size, regardless if the options are even being used.

  4. If a consumer wants to subscribe to the GraphQL events for their own custom purposes using React.useEffect (e.g. to do something in a callback if cache is reloaded while the component is mounted) they have to reinvent wheels that are already implemented inside useGraphQL.

I won't be sure of the final design for the hooks without a lot of work that might also depend on some big changes to the GraphQL client API as well as the SSR API, but here is one idea:

const onGraphQLReset = React.useCallback(
  ({ exceptCacheKey }) => {
    if (cacheKey !== exceptCacheKey) load();
  },
  [load]
);

useOnGraphQLReset(onGraphQLReset);

Add a `GraphQL.reload()` API

A GraphQL.reload() API would trigger a GraphQL reload event, but not actually delete any cache like GraphQL.reset() does. It would have the same ability to preserve the cache for a particular operation via an exceptCacheKey option.

The useGraphQL() React hook option resetOnLoad will need rethinking. Although we could just add another reloadOnLoad option, it doesn't make sense that a user could set both options to true at once.

Use cases:

  • GraphQL.reset():
    • The user logs out, so immediately scrub all their data from the cache. Parts of the page with queries that load on mount, such as the header, will revert to a blank loading status while fresh data is loaded. The exceptCacheKey option is used to ensure that the mutation payload is preserved so that the logout success status and message stays visible to the user.
  • GraphQL.reload():
    • A mutation has happened where parts of the cache could be stale (e.g. the user changed their name), so you want all queries to reload optimistically. They render with their old cache while loading fresh cache in the background, instead of reverting to a blank loading state.

How to override Fetch to do normal fetch request ?

I'm overriding Fetch options to query from REST API.
My options is

const dspaceOptions = {
    url: 'https://jsonplaceholder.typicode.com/todos/1',
    headers: {
      'Content-Type': 'application/json',
      method: 'GET'
    }
  }

But i got error fetch error in cacheValue.
In some cases, my API is from a legacy REST server and i'd love to use this library to do the fetch also.

Prevent unnecessary loading after SSR

At the moment, Query components with the loadOnMount prop automatically fetch fresh data when mounted on the initial page load. This is unnecessary after SSR as the hydrated cache can be assumed to be fresh.

While harmless, and in some cases useful (if data becomes stale in the time it takes the page to load), it would be nice to work out how to prevent this to reduce the burden on servers and reduce client network traffic.

Prevent a React dev warning when a loading Query component is unmounted

If you unmount a Query component (specifically the GraphQLQuery component within it) while it is still loading a query, you see a React dev warning like this:

screen shot 2018-09-26 at 3 23 12 pm

This is because a setState call happens after the request is complete to update the loading state as false, see here. This should be prevented from happening after the component has unmounted.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.