-
Notifications
You must be signed in to change notification settings - Fork 786
React Hooks support #2539
Comments
Looks like the first step to make it happen is to start using the react 16.3 context API, I opened #2540 to address this |
Yes, the |
I started a very basic attempt at hooks here: https://github.com/kristianmandrup/react-apollo/tree/hooks Feel free to continue this effort. So far extracted Query and Mutation as classes so they are not React Components any longer but can be used as standalone classes. Also added dependencies to 16.7 alpha versions of
|
I also opened up this issue here. should I close it? apollographql/apollo-feature-requests#64 |
@lifeiscontent no idea, would love to hear from the maintainers. it makes sense to close one of the issues to keep the discussion in one place, but I don't really know which place is the right one |
The main effort lies in updating the tests to test the hooks. The implementation itself is mostly just wrapping existing functionality with a few changes. I did much of the basic work, but tests remain to be refactored which I've started. See my hooks branch if you want to give it a go. |
I now have ~70% of the grunt work done here. Should be able to get it fully working and all tests passing, with ~3-4 hrs more work... Would love to see someone fork it and continue. Over and out here: midnight in London. |
Added usage docs and examples for current implementation attempt: Apollo Hooks |
I like a lot the proposal 😍 |
Integration with Suspense will also be nice. |
@hyperparsa Suspense is not yet ready to be used with data fetching. |
I created sample hooks to use with Apollo Client: https://github.com/trojanowski/react-apollo-hooks. |
Even though Suspense is not ready for data fetching, isn't it like double work to do it with hooks first and then rewrite to Suspense? I mean if you look at this video from React Conf (time included) it's kinda clear that any data fetching won't be just a simple hook. Andrew even mentions Apollo there and that it should probably wait for a proper implementation. |
@FredyC that's a very good point, that's why it would really be great if the maintainers would share their vision before we go nuts with our implementations and PRs :) I understand the excitement everybody feels about Hooks but we need to plan better what should the ideal API look like @jbaxleyiii |
getting crazy for hooks. Can we resolve this issue on priority basis? |
@prateekrastogi If you are so crazy, just use a package from @trojanowski but be warned it will most likely become obsolete and completely different. |
@FredyC I did checked that package, and that was my only reservation about it. :-) |
I've made a very basic useQuery/useMutation that is working on my medium/large project (not in production yet) https://gist.github.com/maxguzenski/f23f7bba4c726ea5956b17fd3917fa1c |
Any idea when would this be ready? Would be awesome to have an official react-apollo hooks implementation :) |
@juank11memphis I imagine after hooks will be more stable, not alpha 😑 However, I'm also looking forward for this |
@juank11memphis @aralroca Do you realized this isn't actually about hooks? To get the most out of upcoming changes, Apollo should leverage Suspense and that works somewhat differently. Sure, you can use hooks instead of current render prop components, no harm in there and it will work (some working implementations are already done ⬆️ ). However, note that you cannot really suspend rendering with a hook. You have to handle loading states by checking |
Great article: Writing Custom React Hooks for GraphQL https://medium.com/open-graphql/react-hooks-for-graphql-3fa8ebdd6c62 |
Isn't the base of suspense stable since React 16.6? At least the Suspense component is documented in the official React docs. I understood from the linked presentation that the unstable part is the react-cache library which will allow us to easily build suspense-compatible resources. By the base of suspense, I mean a possibility of throwing promises in the render method / functional components and React waits for them to be resolved and shows the fallback UI defined with the
I don't think it's correct. You can throw a promise inside of a hook. My react-apollo-hooks seem to be suspense compatible (you actually have to use it with the |
@trojanowski for what I have seens with react-apollo-hooks, useRef() and other hooks are not saved when you throw the promise, breaking the app in some case. |
@hlehmann Could you please create an issue at https://github.com/trojanowski/react-apollo-hooks/issues with more details? |
This is kind of off topic, but I've been thinking how I could use hooks without waiting for official support.
The full example is in: https://github.com/dai-shi/react-hooks-render-props/tree/master/examples/03_apollo Note that this is an experimental project for fun. |
Since apollo-react 2.3 released yesterday, are there any plans or timeline to give this feature request serious attention for future release? |
Thanks @FreddieRidell for suggestion. I'll just keep |
Have you ever heard about graphql stitching? :) That's generally what solves the "problem" of multiple endpoints, just join those together. It is indeed harder to solve this client side, so that's why there are tools to tackle it elsewhere more gracefully. Nonetheless, this is getting off topic. You are happy with your choice and we are happy what Apollo does for us. It's a win-win ;) |
This is true, but actually handling this client side (if that's a requirement) is very doable with the features already provided by apollo-client and apollo-link. I would recommend that anyone interested in discussing that further check out the Spectrum community and maybe start a new thread there. |
@FredyC, if we will integrate as suggested two object or list queries into one request, it is impossible to refetch data for only one query in that request. @rovansteen:
Yes we are currently discussing future api, hooks seems not yet merged. So array api may be like this: const [ dogs, dogsRefetch, { fetchMore: dogsMore } ] = useQuery(GET_DOGS) It is like just functions. It may be actually considered as function params. It is just params of callback function but converted to return value. Too much functions have some position parameters and object parameters. for example, not need to go so far, fetch('/endpoint', { method: 'GET', headers }) The question is: is it possible to extract some small amount of API as frequently used to position parapeters in tuple? |
The way to use namespacing by prefix in object form: const { lecturer, lecturerRefetch } = useQuery(GET_LECTURER, {prefix: 'lecturer'})
const { studentList, studentListRefetch } = useQuery(GET_SDUDENTLIST, {prefix: 'studentList'}) |
@oklas So because of some theoretical need to run multiple queries in a single component you would have botched the API like that? 😮 Seriously, how many components with multiple We are in the middle of refactoring some medium sized app and there was not a single occasion to need that. If more data is needed, we rather make a single merged query which is way easier to work with (single loading, error...). Sure, there might be some cases where one query depends on another, but I am in favor of separating that into another nested component that receives data from the previous one through props. SRP is a thing :) |
Any component which manage relations between more then one different objects |
This would be a nightmare for the TypeScript/Flow world... 😱 Yea, as I said theoretical until proven otherwise and even then it's upon heavy consideration if that couple of rare cases is worth redesigning API and making it harder for others. |
A quite common and very valid use-case for several queries in one component ist query splitting (see docs here). We have that in our app in a few places. A list view renders items with a little data, then if an item is clicked, the detail view uses a query that gets the data that’s already in cash to display it and a second query to load more data over the network. This is super ugly with HOCs as you can see in the docs. I actually like the list return from hooks as it reflects how useState works, but as already mentioned it will be easy to customize with your own hook. Probably we will refactor all data fetching code out of our components into shared custom hooks that will get data and can be reused to more easily optimize things like query splitting. |
Interesting, I always thought that Apollo is slightly smarter in this and it actually requests only data that are not in cache (unless fetchPolicy dictates otherwise). I was never curious enough to investigate it 😅 Ok, that is certainly a valid case, but still, there isn't probably many of those. Either way, the point is that the current API is not preventing anyone from running multiple queries. It's just slightly less convenient/verbose to do it. And if someone does not like it, there is indeed a super easy way of abstracting it with a custom hook. function useTupleQuery(...) {
const { data, loading, error, ...rest } = useQuery(...)
return [ data, loading, error, rest ]
} It's so tiny that there is no problem to have it copy-pasted in userland code. The beauty is that you can easily choose which variant to use based on the scenario in the component. You can even mix both. Sure, even if API would be other way around, we could do the opposite. The main reason why I don't like that is that the tuple variant will be always more opinionated due to an order of arguments which can be a source of weird errors. |
This ^ Imagine if the <Query {...props}>
{([i, dont, know, the, order]) => <Thing />}
</Query> That looks so weird, but now with hooks it's suddenly different. Maybe the best thing is just to keep the API similar to the |
As far as bikeshedding the API of the tuple goes, I think to align with the native hooks, const [{ data, loading, error, ...rest }, refetch] = useQuery(...) makes the most sense, considering most are in the form of |
For anyone interested, here's the const [action, data, loading, error] = useFetchQL(
{key, query, mutation, subscription,...}, callback
) Surprisingly, there's no difference at all between Here's another use of const [data] = useFetchQL({
key: 'top-10-posts',
fetch: async () => {
const url = 'https://jsonplaceholder.typicode.com/posts?_page=1&_limit=10'
return await fetch(url)
}
}); It supports generic async call, too. So, let's just see that, don't treat graphql at any difference with another. From the consumer point of view, |
Easy expansion of the existing API with format-like method(s): const [data, refetch] = useQuery(...).asState() |
@oklas I don't think it's even worth considering to include that in the core. Same reason why React does not include hundreds of utility hooks. Everyone has different needs and opinions on how API should look like. It's great we have custom hooks and you can shape it however you like without bothering others with it. Let's stop this discussion as it doesn't really lead to any useful end. |
@FredyC if what you’re saying is: react-Apollo should have an official hooks implementation, but that we should stop quibbling as to the exact syntax, because anybody can wrap that to their liking. Then I agree! Nearly any official react-apollo hooks strategy is enough here! |
Maybe the return value can try this: function useQuery() {
// ...
const ret = [data, loading, error]; // or something else
ret.data = data;
ret.loading = loading;
ret.error = error;
// or something else
return ret;
}
const [data, loading, error] = useQuery(); // work
const { data, loading, error } = useQuery(); // also work |
This is very good: const [{ data, loading, error, ...rest }, refetch] = useQuery(...); If the array has more than two elements, it's going to be a little tricky. For example, I just want one and four: // Get all :
const [data, loading, error,refetch] = useQuery();
// Get one and four. This is bad
const [data, , ,refetch] = useQuery(); |
Valid syntax for eliding members when destructuring is: const [data, , , refetch] = useQuery(); |
Please, let's leave these ideas of tuples. The I don't really follow why is so hard for you to just do this in your app/lib code. It's an absolute win-win for everyone. function useTupleQuery(...) {
const { data, loading, error, refetch, ...rest } = useQuery(...)
return [ data, loading, error, refetch, rest ]
} |
@hwillson Thoughts on locking this thread and moving these other discussions over to apollo's official Spectrum channels? I'm subscribed to this thread to receive updates on the official hooks implementation, and these other convos are blowing up my notifications. Sure I can unsubscribe, but than I lose visibility on the updates I'm really here to receive like: |
First off kudos to the Apollo team with the updates and clear roadmap. I've used Apollo on a few projects and it's worked great. We've been working on a project graphql-hooks. It's a super lightweight GraphQL client with first class hooks support. We'd love to get some feedback, and if anyone would like to get involved please get in touch! PS: great job on |
We use multiple GraphQL queries in a single component quite a lot in our large app. |
I sketch out basic implementation here const [{
json, error, loading
}, {
refetch, abort, setQuery, setTimeout, setVariables, setInit, setOperationName
}] = useGraphql({
key, url, query, variables, operationName, init, skip, timeout
}, {onComplete, onError, onAborted}) The benefit is, we can easily change everything we want, from query, timeout, variables, headers, operation name in one component. With this, a custom GraphiQL is easily done ! |
@revskill10 Seriously man, no offense, but nobody cares about your "I use graphql like a fetch", so please stop spamming with it and spreading it like some holy grail. If you really like it, make your own lib and perhaps you will be famous, but it's not funny anymore. |
@hwillson please lock the thread! |
There has been a lot of great discussion here, but this thread is definitely getting a bit unwieldy. We'll lock it for now, and post back when we have updates to share. Let's keep the discussion going over in https://spectrum.chat/apollo. Thanks! |
Hooks support is almost ready. Anyone interested can follow along in #2892. We'll be merging into master very shortly, and releasing as soon as we get the docs updated. Thanks all! |
I'd like to start a discussion about the possible next-gen API based on react hooks for
react-apollo
.I think this API brings a perfect opportunity for
react-apollo
to improve already excellent DX even more.What do you guys think?
The text was updated successfully, but these errors were encountered: