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

Improve types in Query component. Make data be undefined in initial load #1581

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions src/Query.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ const shallowEqual = require('fbjs/lib/shallowEqual');
const invariant = require('invariant');
const pick = require('lodash/pick');

function observableQueryFields(observable) {
type ObservableQueryFields<TData> = Pick<ObservableQuery<TData>, 'refetch' | 'fetchMore' | 'updateQuery' | 'startPolling' | 'stopPolling'>;

function observableQueryFields<TData>(observable: ObservableQuery<TData>): ObservableQueryFields<TData> {
const fields = pick(
observable,
'refetch',
Expand All @@ -38,39 +40,43 @@ function observableQueryFields(observable) {
return fields;
}

export interface QueryResult<TData = any> {
function isDataFilled<TData>(data: {} | TData): data is TData {
return Object.keys(data).length > 0;
}

export interface QueryResult<TData = any, TVariables = OperationVariables> {
client: ApolloClient<any>;
data: TData;
data?: TData;
error?: ApolloError;
fetchMore: (
fetchMoreOptions: FetchMoreQueryOptions & FetchMoreOptions,
) => Promise<ApolloQueryResult<any>>;
loading: boolean;
networkStatus: number;
refetch: (variables?: OperationVariables) => Promise<ApolloQueryResult<any>>;
refetch: (variables?: TVariables) => Promise<ApolloQueryResult<any>>;
startPolling: (pollInterval: number) => void;
stopPolling: () => void;
updateQuery: (
mapFn: (previousQueryResult: any, options: UpdateQueryOptions) => any,
) => void;
}

export interface QueryProps<TData = any> {
children: (result: QueryResult<TData>) => React.ReactNode;
export interface QueryProps<TData = any, TVariables = OperationVariables> {
children: (result: QueryResult<TData, TVariables>) => React.ReactNode;
fetchPolicy?: FetchPolicy;
notifyOnNetworkStatusChange?: boolean;
pollInterval?: number;
query: DocumentNode;
variables?: OperationVariables;
variables?: TVariables;
ssr?: boolean;
}

export interface QueryState<TData = any> {
result: ApolloCurrentResult<TData>;
}

class Query<TData = any> extends React.Component<
QueryProps<TData>,
class Query<TData = any, TVariables = OperationVariables> extends React.Component<
QueryProps<TData, TVariables>,
QueryState<TData>
> {
static contextTypes = {
Expand All @@ -82,7 +88,7 @@ class Query<TData = any> extends React.Component<
private queryObservable: ObservableQuery<TData>;
private querySubscription: ZenObservable.Subscription;

constructor(props: QueryProps<TData>, context: any) {
constructor(props: QueryProps<TData, TVariables>, context: any) {
super(props, context);

invariant(
Expand Down Expand Up @@ -197,12 +203,12 @@ class Query<TData = any> extends React.Component<
this.setState({ result: this.queryObservable.currentResult() });
};

private getQueryResult = (): QueryResult<TData> => {
private getQueryResult = (): QueryResult<TData, TVariables> => {
const { result } = this.state;
const { loading, error, networkStatus, data } = result;
return {
client: this.client,
data,
data: isDataFilled(data) ? data : undefined,
loading,
error,
networkStatus,
Expand Down
2 changes: 1 addition & 1 deletion test/client/Query.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ describe('Query component', () => {
{result => {
catchAsyncError(done, () => {
expect(result.loading).toBeFalsy();
expect(result.data).toEqual({});
expect(result.data).toBeUndefined();
expect(result.networkStatus).toBe(7);
done();
});
Expand Down
6 changes: 2 additions & 4 deletions test/client/__snapshots__/Query.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ Object {
}
`;

exports[
`Query component calls the children prop: result in render prop while loading 1`
] = `
exports[`Query component calls the children prop: result in render prop while loading 1`] = `
Object {
"data": Object {},
"data": undefined,
"error": undefined,
"fetchMore": [Function],
"loading": true,
Expand Down
10 changes: 5 additions & 5 deletions test/server/getDataFromTree.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -939,11 +939,11 @@ describe('SSR', () => {
}
}
`;
const data = { currentUser: { firstName: 'James' } };
const resultData = { currentUser: { firstName: 'James' } };
const variables = { id: 1 };
const link = mockSingleLink({
request: { query, variables },
result: { data },
result: { data: resultData },
delay: 50,
});

Expand All @@ -959,12 +959,12 @@ describe('SSR', () => {
};
}

class CurrentUserQuery extends Query<Data> {}
class CurrentUserQuery extends Query<Data, { id: number }> {}

const Element = (props: { id: number }) => (
<CurrentUserQuery query={query} ssr={false} variables={props}>
{({ data: { currentUser }, loading }) => (
<div>{loading ? 'loading' : currentUser.firstName}</div>
{({ data, loading }) => (
<div>{loading || !data ? 'loading' : data.currentUser.firstName}</div>
)}
</CurrentUserQuery>
);
Expand Down