Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

[@apollo/react-hooks] can data be undefined? #3192

Closed
FezVrasta opened this issue Jun 27, 2019 · 8 comments
Closed

[@apollo/react-hooks] can data be undefined? #3192

FezVrasta opened this issue Jun 27, 2019 · 8 comments
Assignees
Milestone

Comments

@FezVrasta
Copy link

Intended outcome:

I'm using @apollo/react-hooks#useQuery and I noticed sometimes data can be set to undefined. I would expect it to always return an object, even if empty during loading or in case of errors.

Actual outcome:

data can be undefined, I don't understand if this is expected?

How to reproduce the issue:

const { data } = useQuery(QUERY);

if (data === undefined)
  throw new Error('found undefined data');
}

Version

@apollo/react-hooks@0.1.0-beta.10

@hwillson hwillson self-assigned this Jun 27, 2019
@hwillson hwillson added this to the Release 3.0 milestone Jun 27, 2019
@pleunv
Copy link

pleunv commented Jun 27, 2019

This has been a topic of discussion before, but as far as I remember it was decided to not return an empty object by default as this would be a pretty big breaking change and cause quite some issues for existing code, I'm not sure if this behavior is changing now with 3.0. Also keep in mind that when a query errors you will most likely get undefined as well.

The docs & types also reflect this:

data: TData
An object containing the result of your GraphQL query. Defaults to undefined.

edit: Also see #2424

@FezVrasta
Copy link
Author

FezVrasta commented Jun 27, 2019

Thanks for the answer, I notice most often than not, data is set to an empty object though... Is this expected?

Anyways, this can be easily tweaked by doing:

const { data = {} } = useQuery(QUERY);

to say that it's not a big issue, and may actually be a good thing so that people who prefer to get undefined have it, and people who prefer an empty object can easily achieve that with 3 additional characters.

@pleunv
Copy link

pleunv commented Jun 27, 2019

I'm not sure, I think the behavior is pretty inconsistent and depends on errors, cache, etc. I'm always checking whether data exists before accessing as we've been bitten by it before and I'd suggest you do the same :)

@hwillson
Copy link
Member

Thanks for reporting this @FezVrasta. Yes, this is a bit annoying for sure; we need to align this across the board.

@hwillson
Copy link
Member

Okay, here's how things are currently setup in master (not all of this is available in the current beta but will be shortly):

  • When results are loading, data is set to {}. Technically speaking undefined is more correct (since the data doesn't exist yet), but setting data to {} does help avoid extra data is truthy checks (the approach is a little more developer friendly). A good way to look at the initial {} is that it's the result of useQuery getting the data ready to hold values (it's prepping data as a container).

  • If an error occurs and a last data result is available, the last data result is re-used. If the last data result isn't available, data is undefined. We don't want to set data to {} here, as we're not getting data ready to hold results; an error has occurred and we have no data, so undefined seems like a better fit.

  • If the skip option is set to true, data is undefined. So again since we're not prepping data to hold a result (since we're skipping running the query), undefined seems like a better choice.

  • The initial data value when using SSR has been aligned to match the client side equivalent. So it will be {} when loading on the server as well.

The above is the current approach we're planning on launching with React Apollo 3. While not perfect, it seems to be the best way to meet in the middle of developer usability and correctness. @FezVrasta the above means that the example you provided earlier in this issue thread would never throw the error, as data would be {}.

If anyone objects to this approach definitely let me know. Thanks!

@levrik
Copy link

levrik commented Jul 31, 2019

@hwillson I was just trying out the Apollo hooks package for the first time while migrating away from graphql-hooks. I tried urql before moving on to Apollo.
Both other clients return undefined as data before the first successful fetch.
I was quite confused by this. I'm using TypeScript and now I have to check if data is there, because it's defined as | undefined, then I have to check my top-level object of my query projects if it's there. For the case data is {}.
Also in that case that data is just {}, the typings fail.
Basically it enforces me to make sure data isn't undefined but it just accepts data.projects to be there which isn't true for this initial state. Now I have to remember as a developer to check that because I'm getting runtime errors.
That all is quite unintuitive. Any suggestions how to use the Apollo hooks with TypeScript?

@mateja176
Copy link

@hwillson It's okay for data to be {} while the operation is in progress however I would much rather have data stay {}. In fact, compared the the current combination, I'd also prefer if data were undefined in both cases. The added consistency makes the whole concept easier to grasp and explain to others.

P.S. Adding an initial value for the data might encompass the best of both worlds

@hwillson
Copy link
Member

hwillson commented Sep 3, 2019

@mateja176 We're changing things around so data is always undefined where there is no data. See #3388.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants