Giter VIP home page Giter VIP logo

react-apollo-hooks'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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-apollo-hooks's Issues

Merging into react-apollo?

Were you planning on or Would you object to somebody taking this repo and trying to contribute this back to react-apollo?

I love what you've started here, and I want to help!

Suspense and server side rendering

Hello,

I was curious if you knew what the behavior would be like if this package was used with server side rendering.

My understanding is that Suspense is not currently supported when server side rendering. I think it shows loading state for Suspense components. I'm not sure how the interaction will play out when used in combination with the data collector from Apollo Server.

Do you happen to have any insight on this? Thank you.

Invalid syntax in readme `Suspense` example

Regarding this snippet:

import React, { Suspense } from 'react';

const MyComponent = () => {
  return (
    return (
      <Suspense fallback={<div>Loading...</div>}>
        <Dogs />
      </Suspense>
    )
  );
}

return statements are not valid in an expression context, and it seems like the example could be rewritten as:

const MyComponent = () => (
  <Suspense fallback={<div>Loading...</div>}>
    <Dogs />
  </Suspense>
);

server side rendering implementation questions/discussion

some questions / concerns

  1. how is server-side data hydrated? current API combines walking tree / rendering markup, so the data is private to apollo-react-hooks. I also tried running the latest release and the client markup was incorrectly rendered.
  2. how is server-side data processed? I'm not too familiar with react-apollo internals, but was looking at getMarkupFromTree code and doing ssrManager.consumeAndAwaitPromises().then(process); seemed weird, there doesn't seem to be a base case so you're essentially calling the render function until the promises are finished? perhaps i didn't look at the code enough, or I don't fully understand the way suspense works, but my superficial reaction was that something looks off.

in regards to point 1, an alternative can be to expose a ServerApolloProvider that includes the ApolloContext and SSRContext. that way getDataFromTree and renderToString can be separate

handling server side graphql errors without suspense

with getDataFromTree you could wrap the call in a try-catch block to prevent graphql errors from crashing app, since you could still render the html markup

but since getDataFromMarkup combines fetching data and rendering html, how should server side graphql errros be handled if you're not yet using suspense?

Another mutation type issue

When you use the "update"property in mutation options like :

const myMut = useMutation<MyMut, MyMutVars>(MYMUT, {
    update: (cache, result) => {
        //// result has type FetchResult<MyMut>
        //// result.data has type ExecutionResult<ExecutionResultDataDefault> instead of an expected ExecutionResult<MyMut>
    }
});

I think the problem comes again from the FetchResult type as defined in apollo-link. The only workarround I think is to redefine MutationOptions/MutationUpdaterFn type to use the FetchResult type you already redefine. :s

onCompleted and onError not working with mutation

Hey, great library.

I'm trying to catch mutation errors but it seems none of the callbacks are called. The only way I was able to catch errors is to use errorPolicy: "ignore" and then checking the result in refetchQueries callback.

Is it an error or am I doing something wrong?

addUser = useMutation(mutation, {
    update: (proxy, mutationResult) => {
       /* NOT CALLED */
    },
    refetchQueries: (result) => {
      /* CALLED ON errorPolicy: "ignore" */
    },
    onCompleted: (data) => {
       /* NOT CALLED */
    },
    onError: (data) => {
       /* NOT CALLED */
    }
  });

can't set notifyOnNetworkStatusChange with typescript

export function useQuery<TData = any, TVariables = OperationVariables>(
  query: DocumentNode,
  // QueryHookOptions
  options?: QueryHookOptions<TVariables>
): ApolloQueryResult<TData> & {
  fetchMore<K extends keyof TVariables>(
    fetchMoreOptions: FetchMoreQueryOptions<TVariables, K> &
      FetchMoreOptions<TData, TVariables>
  ): Promise<ApolloQueryResult<TData>>;
};


type QueryHookOptions<TVariables> = Omit<QueryOptions<TVariables>, 'query'> & {
  suspend?: boolean;
};

current workaround

useQuery<A, B>(Query, { notifyOnNetworkStatusChange: true } as any);

what I expected

useQuery<A, B>(Query, { notifyOnNetworkStatusChange: true });

index.d.ts

// now
type QueryHookOptions<TVariables> = Omit<QueryOptions<TVariables>, 'query'> & {
  suspend?: boolean;
};

// should be
type QueryHookOptions<TVariables> = Omit<WatchQueryOptions<TVariables>, 'query'> & {
  suspend?: boolean;
};


export interface QueryOptions<TVariables = OperationVariables> extends QueryBaseOptions<TVariables> {
    query: DocumentNode;
    metadata?: any;
    context?: any;
}
export interface ModifiableWatchQueryOptions<TVariables = OperationVariables> extends QueryBaseOptions<TVariables> {
    pollInterval?: number;
    notifyOnNetworkStatusChange?: boolean;
}
export interface WatchQueryOptions<TVariables = OperationVariables> extends QueryOptions<TVariables>, ModifiableWatchQueryOptions<TVariables> {
}

cause in index.js, useQuery calls watchQuery so restOptions should have WatchQueryOptions interface too

export function useQuery(query,
  {
    variables,
    suspend = true,
    context: apolloContextOptions,
    ...restOptions
  } = {}
) { 
// ...
// ...
  const watchedQuery = client.watchQuery({
      query,
      variables,
      ...restOptions,
    });
// ...
 }

PS

how can i skip query?

<Query {...options} skip={true}>{renderProps}</Query>
// vs
useQuery<A, B>(Query, { skip: true } as any); // not work cause apolloClient dosn't have skip option

ApolloQueryResult type with wrong property

In ApolloQueryResult type property errors should be singular just an error.

export declare type ApolloQueryResult = {
data: T;
error?: GraphQLError[]; //Changed
loading: boolean;
networkStatus: NetworkStatus;
stale: boolean;
};

Prop data from query result should not be optional

I think the property data from useQuery result should not be optional.
When we look in the docs:

An object containing the result of your GraphQL query. Defaults to an empty object.

It defaults to an empty {} object. Event when I console.log, I never see data being undefined.

Apollo itself defines it as

ApolloCurrentResult<T> = {
    data: T | {};
}

and

ApolloQueryResult<T> = {
    data: T;
}

As we can see, it is either T or {} but never optional (undefined)
Thus the interface QueryHookState should not define data as optional.

Manually call useQuery In useEffect()

Can someone share a way to implement the use of useQuery within a useEffect method?

I would think there would be a way to initiate a query again based on an attribute that has been changed that an Effect is listening to.

As a basic example: 2 Dropdowns, where the first dropdown's selection needs to update the options in the second dropdown. (Country, Region)

How to deal with suspend?

I am mostly curious what was the initial motivation to have suspend = true by default already. There is a lack of information on how to actually use suspense for data fetching considering that it's planned for late 2019.

I just got burned by this badly when I forgot to set it false for one component deep down in the tree. I do have a Suspense way up in a tree to handle React.lazy. Suddenly when a query was rerun due to variables changing, everything got unmounted and fallback to top-level Suspense. It took me a while and some debugging to realize the culprit.

Do you have some actual examples of how to integrate it with react-apollo-hooks? Is it someone using it successfully already or is it everyone switching it off?

Let's consider a pretty simple scenario. A component that has useQuery and renders some markup with data from that query. Now with loading prop the decision what to show is done deeper in the tree. However, with suspension in play, it has to be done at top levels? I just cannot wrap my head around this for some reason.

Mutation refetch query data not reflected in v0.3.0

I have a mutation with refetchQueries whose data is directly impacted by the mutation. With the latest v0.3.0 update those queries no longer correctly pull the updated data even though the network tab shows the correct data being returned from the server. I can force other queries to execute by navigating back and forth between another page and the data successfully updates the second time.

Rolled back to v0.2.1 and everything works as expected. Will work on debugging further.

Looks like the ObservableQuery gets torn down (tornDown = true) after the last subscriber is removed but the new code still keeps it in query cache. This query will never return updated data.

Rethrow apollo errors and recommend error boundaries

Right now errors are returned as a part of the useQuery result. Maybe a better idea would be to throw them and recommend to use Error Boundaries instead (at least in the suspense mode).

So instead of this code:

const Hello = () => {
  const { data, error } = useQuery(GET_HELLO);
  if (error) return `Error! ${error.message}`;

  return <p>{data.hello.world}</p>;
};

we could write:

const Hello = () => {
  // we can be sure here that the error hasn't occurred
  return <p>{data.hello.world}</p>;
};

and use an error boundary at the root of the react tree (or anywhere else above the component) - similar to how we use the <Suspense /> component.

Use with React 16.8.0

Been using this library for a while now and it's been perfect 👌

I just upgraded to the latest stable release of React 16.8.0 and then my console was full of errors saying:

Rendered more hooks than during the previous render. This is not currently supported and may lead to unexpected behavior.

After debugging i found it only happens when the component is wrapped in a memo()

Not sure where the issue should be posted though?

Adding hooks for apollo-link-state

Curious if you'd be interested in adding hooks for Apollo Link State? I've struggled a bit with finding a simple/repeatable way to use it, and hooks seem like they may be exactly what the doctor ordered.

Please add a TypeScript definition file

Perhaps to start with, something as simple as:

declare module "react-apollo-hooks" {
  function ApolloProvider({ children, client }: any): any;
  function useApolloClient(): any;
  function useApolloQuery(query: any, { variables }?: any): any;
  function useApolloMutation(mutation: any, baseOptions?: any): any;
}

fetchPolicy in ApolloClient's defaultOptions being ignored

I'm using the defaultOptions option on ApolloClient to make all queries default to a cache-and-network policy:

  defaultOptions: {
    query: {
      fetchPolicy: "cache-and-network"
    },
    watchQuery: {
      fetchPolicy: "cache-and-network"
    }
  }

When using React Apollo directly (either via the graphql() HOC or the <Query /> component), my queries are automatically being executed whenever my component mounts. However, using useQuery only executes the query if the cache is empty. If I explicitly pass fetchPolicy: "cache-and-network" as an option to useQuery it works fine, but I'm not sure why the defaults set on the ApolloClient instance are being overridden?

useQuery with suspend=false does not keep polling after error

Trying to run the following code:

const Status: React.FunctionComponent = () => {
    const { data, errors } = useQuery(STATUS_QUERY, { suspend: false, pollInterval: 2000 });

    console.log(data);
    console.log(errors);

    if (errors && errors.length > 0) {
        return <WarningIcon fontSize="large" />;
    }

    return null;
};

When the query fails (e.g. when server is down) it stops polling.

Unhandled error Network error: Failed to fetch Error: Network error: Failed to fetch at new ApolloError

With react-apollo's Query component I can keep polling.

Let me know if you need more info

Missing type definition for `error` in the return type of `useQuery`

When the following simple query is compiled with Typescript:

const Demo = () => {
   const { data, error, loading } = useQuery(GET_DEMOS)
}

Typescript complains about error not being found on the return type of useQuery, error message is as follows:

Property 'error' does not exist on type 'ApolloQueryResult<any> & 
Pick<ObservableQuery<any, OperationVariables>, "refetch" | "startPolling" | "stopPolling" | "updateQuery"> & 
{ fetchMore<K extends string | number>(fetchMoreOptions: FetchMoreQueryOptions<...> &  FetchMoreOptions<...>): Promise<...>; }'.

The definition of ApolloQueryResult can be found in the apollo-client repo, and apparently only errors are defined there. Changing error to errors in the code above does fix the problem. However, to maintain consistency with react-apollo, it would be great to define error.

Nested query immediately freezes tests

First of all, great job on the package!

I'm currently writing tests for an application made with react-apollo-hooks, but I'm running into the issue where Jest simply freezes when I try to test queries that are deeper than one level, e.g.:

query HelloQuery {
  hello {
    world
  }
}

I've tried to make a CodeSandbox of the issue, using @trojanowski example for tests, but please mind that CodeSandbox will try to run the tests immediately and in this case freeze the page entirely, so close the browser preview before the tests run:

https://codesandbox.io/s/40j6v77op4

Can't access to mutation type

I'm trying to pass a mutation function to a function using typescript, the problem is that when I try to pass the mutation I don't know which type should I use.

const loginMutation = useMutation(loginQuery, {
  variables: { email, password },
});

export const loginAction: LoginAction = async (
  loginMutation, // Which type loginMutation should I assign here?
) => {
  try {
    const { data } = await loginMutation();
    console.log(data.login.token);
  } catch (error) {
    console.error(error)
  }
};

Feat: Key prop in useMutation to update item in the cache

With react-apollo, it's possible to set a key={id} prop on the Mutation component

e.g

	<Mutation mutation={UPDATE_TODO} key={id}>

Apollo then updates the correct item in the cache, wondering if this is currently possible with this library?

After refetch is done, component is not re-rendered

I got a repro here which I made for the article (in works): https://codesandbox.io/embed/qzjzr583yq

Watch the console

  1. first image loads just fine
  2. in the input on top enter some other value, eg. "kitten"
  3. different image is loaded
  4. change the input back to any other value
  5. refetch is executed, data arrive and yet no re-render happens
  6. changing input again and it's the same, new data are flowing, but are not processed

Now the strangest part is that if you click on the little button to refresh same tag, it works perfectly.

If there is some mistake on my part, I do apologize, but I wasn't able to spot it.

You can also see error reported in #74 in here if you enter some tag that has no giphy associated.

how to check if fetching more, network status undefined

Using the query as

  const { data, loading, networkStatus, fetchMore } = useQuery(query, {
    variables,
    skip,
    notifyOnNetworkStatusChange: true
  });

networkStatus seems undefined when console logging so I can't do const loadingMore = networkStatus === 3

Usage with Storybook

Hello,

I'd like to use react-apollo-hooks with Storybook.

I saw your example for testing, but in the context of Storybook I can't call waitForNextTick.

So I'm stuck in the Loading state when trying to build my component in isolation :

import { Suspense } from 'react'
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { MockLink } from 'apollo-link-mock'
import { ApolloProvider } from 'react-apollo-hooks'
import { storiesOf } from '@storybook/react'
import { GET_BOITE, BoiteDetails } from './BoiteDetails'

let MOCKS = [
  {
    request: {
      query: GET_BOITE,
      variables: { where: { id: '123' } }
    },
    result: {
      data: {
        id: '123',
        libelle: 'Boite 123'
      }
    }
  }
]

let addApolloProvider = mocks => story => {
  let client = new ApolloClient({
    cache: new InMemoryCache(),
    link: new MockLink(mocks)
  })
  return (
    <Suspense fallback="Loading...">
      <ApolloProvider client={client}>{story()}</ApolloProvider>
    </Suspense>
  )
}

storiesOf('Parametres/Boites', module)
  .addDecorator(addApolloProvider(MOCKS))
  .add("Détails d'une boite", () => <BoiteDetails id="123" />)

Roadmap to complete stable version

I’m trying to figure out a list to make react-apollo-hooks analogue to current react-apollo version.

List from @trojanowski (#40 (comment)):

  • useSubscription (#22 and #37)
  • skip option for useQuery (#21)
  • server-side rendering (#8) - also with react-apollo compatibility
  • TypeScript rewrite (#39)
  • (probably) changes to error management (#28)

My observations (open for suggestions)

  • Refactor client+query caching: use react context, add error messages (inherit from react-apollo).
  • Add more tests with react-profiler (started in #42).
  • Add tests from react-apollo (maybe fix some edge cases).
  • Bundle with rollup, report bundle size.
  • Add tests for useQuery imperative methods.
  • Find a good way to replace lodash with interal utilities.
  • Add more recipes and examples (most developers mindset is not prepared for hooks and Suspense yet).

PRs:

  • TypeScript Rewrite (#39)
  • useSubscription (#37)
  • SSR (#44)
  • Skip option for useQuery (#21)
  • Support all fetch policies in suspense mode (#15)

Update query result after mutation

Hello,

I'm trying to see my mutation after writing a query into the store.
Previously on a mutation update when I write something to the store with writeQuery all queries results were updated automatically on screen.

It seems that now useQuery is not called twice on rerender when no input args changed. I found a workaround something like this :
const { data, refetch, fetchMore } = useQuery(POST_FEED, { variables: variables, key: something });

And on each mutation I change the key value. But I don't think it's the solution for the problem.

Conditionally firing a query

I am trying to implement a conditional pattern which I am not sure how it should work with hooks.
I have one query asking for currentUser and only when and if it returns a userId I will execute the query.

By the rules of hooks, you must not nest hooks inside conditions or loops, so how can I achieve this?

This is a sample of my custom hook:

function useSomething() { 
  const [userId] = useCurrentUser();
  // Here we need to skip the query
  const { data, errors } = useQuery(query, { variables: {userId} });
  // Do some stuff and return data
 return [data, errors]
}

Hooks can only be called inside the body of a function component.

I'm able to query without issue, but am getting the error

Hooks can only be called inside the body of a function component.

when trying to perform a mutation.

  const mutate = (variables) => {
    const mut = useMutation(UPDATE, { variables });
    mut();
  };
  return (
    <Details update={mutate} {...otherProps} />
  );
};
    "apollo-cache-inmemory": "^1.3.12",
    "apollo-client": "^2.4.8",
    "apollo-link": "^1.2.6",
    "apollo-link-http": "^1.5.9",
    "apollo-link-mock": "^1.0.1",
    "apollo-link-ws": "^1.0.12",
    "apollo-utilities": "^1.0.27",
    "react-apollo": "^2.3.3",
    "react-apollo-hooks": "^0.2.1",
    "react-dom": "^16.8.0-alpha.0",
    "react-scripts": "^2.1.3-next.6a95aae9",```

return memoized value

currently returned value both of useMutation and useQuery calculated every time they called, I'm not really familiar with apollo logics, but I guess this can memoized?, for instance useMutation should be similar like this:

export function useMutation(mutation, baseOptions) {
  const previousOptions = useRef();
  const client = useApolloClient();
  const result = isEqual(previousOptions.current, baseOptions);
  return useMemo(
    () => {
      previousOptions.current = baseOptions;
      return localOptions => client.mutate({
        mutation,
        ...baseOptions,
        ...localOptions,
      });
    },
    [
      mutation,
      result ? previousOptions.current : baseOptions,
    ],
  );
}

Using fetchPolicy: 'cache-and-network' creates infinite loop

Using the options cache-and-network for fetch policy creates an infinite loop.

I could see that in this if:

query === previousQuery.current &&
isEqual(variables, previousVariables.current) &&
isEqual(apolloContextOptions, previousApolloContextOptions.current) &&
isEqual(restOptions, previousRestOptions.current)

previousVariables.current and previousRestOptions.current and always undefined.

I don't know why useRef is not persisting.

Using it with the Appsync client

Hi, I guess it's just not possible right now, but just to confirm I didn't do anything wrong:

import { ApolloProvider } from "react-apollo-hooks";
import { Rehydrated } from "aws-appsync-react";
import appsyncClient from "./appsyncClient";

<ApolloProvider client={appsyncClient}>
    <Rehydrated>
      <App />
    </Rehydrated>
</ApolloProvider>

throws the following error:

Unhandled Rejection (TypeError): Cannot read property 'hydrated' of undefined

If I use the ApolloProvider from react-apollo, it works fine. I don't know how difficult it would be to add support for it.

Thanks.

useQuery causes a component to render multiple times

Is it normal with this new hooks api to re-render a component multiple times? I just saw that useQuery causes a component to re-render 3 times. Here is an example: https://codesandbox.io/s/j7kw103525

It's the same, example from the readme file, I have just added a console log to /views/Details.js

const Detail = ({
  match: {
    params: { breed, id }
  }
}) => {
  const { data, error } = useQuery(GET_DOG, {
    variables: { breed }
  });
  console.log(2);
  return (
    <View style={styles.container}>
      <Header text={breed} />
      {error ? (
        <Error />
      ) : (
        <DogList...

And the output is:
2
2
2

I have tried on my own project and got the same result.

useQuery does not return data on refetch after error.

Steps to reproduce:

  1. Make a successful request
  2. Take graphql server offline
  3. Make a new request
  4. We get an error now.
  5. Take graphql server online
  6. Invoke refetch.
  7. Note the successful network request in devtools, but we never get data back from useQuery.

fetchPolicy="network-only" still returns data from the cache

It seems like even when I'm using network-only that data from the cache is being returned immediately. I would have expected that the rendering phases would be:

{ data: {},           loading: true }  // render 1
{ data: { foo: {} }, loading: false } // render 2
// done

Instead what happens is that if data from the cache exists, at render 1 data will actually be populated with the cache data.

The React Apollo docs make it clear this should never happen:

network-only: This fetch policy will never return you initial data from the cache. Instead it will always make a request using your network interface to the server. This fetch policy optimizes for data consistency with the server, but at the cost of an instant response to the user when one is available.

For now I'm using a wrapper that returns {} when loading=true and fetchPolicy=no-cache or fetchPolicy=network-only.

Make useQuery work with with getDataFromTree (server side rendering)

I am using next.js with Apollo, and have been writing Hooks based components. I noticed react-apollo-hooks doesn't seem to work with getDataFromTree when it does SSR and fills the cache. If I use from react-apollo it correctly sets the initial data in the apollo cache and doesn't refetch it, but useQuery only seems to fetch client side... is this expected/going to be fixed?

Rename hooks

It is necessary to include the Apollo word in function names? I think it would be much cleaner without it

useQuery

useMutation

We could have both and deprecate the old names with a message.

SuspenseProps is imported in SuspenseSSR but react doesn't have it.

I updated to latest version 0.3.0 and saw below error being thrown. I thought that maybe it's something new added to React 16.8.0-alpha but no. What is this SuspenseProps imported from 'react'?

.../node_modules/react-apollo-hooks/lib/SuspenseSSR.d.ts
Type error: Module '".../node_modules/@types/react/index"' has no exported member 'SuspenseProps'. TS2305

1 | import { SuspenseProps } from 'react';
| ^
2 | export declare function unstable_SuspenseSSR({ children, fallback }: SuspenseProps): JSX.Element;

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.