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

Commit

Permalink
Add support for client in options (#729)
Browse files Browse the repository at this point in the history
* add support for client in options

Adds support for client in graphql HoC to support usecases with more than one ApolloClient

* Client is no longer required in context because it can get passed via options.

* Dont use calculateOptions if using a mutation.

Because it checks if variables are present

* Use mapProps instead of calcluateOptions for componentWillReceiveProps.

* Update client if client props change.

* Skip-Test now no longer expects option.client to be not accesed.

* Add test for client in options.

* Update Changelog.md
  • Loading branch information
flexzuu authored and James Baxley committed Jul 5, 2017
1 parent f847d08 commit 23d131a
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 7 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Change log

### vNext
- Feature: You can now supply a client in options object passed to the `graphql` high oder component. [PR #729]

### 1.4.2
- Fix: Fix component reference and variable statement for flow types
Expand Down
23 changes: 18 additions & 5 deletions src/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ export declare interface MutationOpts {
variables?: Object;
optimisticResponse?: Object;
updateQueries?: MutationQueryReducersMap;
client?: ApolloClient;
}

export declare interface QueryOpts {
ssr?: boolean;
variables?: { [key: string]: any };
fetchPolicy?: FetchPolicy;
pollInterval?: number;
client?: ApolloClient;
// deprecated
skip?: boolean;
}
Expand Down Expand Up @@ -161,7 +163,7 @@ export default function graphql<TResult = {}, TProps = {}, TChildProps = Default
static displayName = graphQLDisplayName;
static WrappedComponent = WrappedComponent;
static contextTypes = {
client: PropTypes.object.isRequired,
client: PropTypes.object,
};

// react / redux and react dev tools (HMR) needs
Expand Down Expand Up @@ -191,7 +193,13 @@ export default function graphql<TResult = {}, TProps = {}, TChildProps = Default
constructor(props, context) {
super(props, context);
this.version = version;
this.client = context.client;

const { client } = mapPropsToOptions(props);
if (client) {
this.client = client;
} else {
this.client = context.client;
}

invariant(!!this.client,
`Could not find "client" in the context of ` +
Expand Down Expand Up @@ -219,14 +227,19 @@ export default function graphql<TResult = {}, TProps = {}, TChildProps = Default
}

componentWillReceiveProps(nextProps, nextContext) {
if (shallowEqual(this.props, nextProps) && this.client === nextContext.client) {
const { client } = mapPropsToOptions(nextProps);
if (shallowEqual(this.props, nextProps) && (this.client === client || this.client === nextContext.client)) {
return;
}

this.shouldRerender = true;

if (this.client !== nextContext.client) {
this.client = nextContext.client;
if (this.client !== client && this.client !== nextContext.client) {
if (client) {
this.client = client;
} else {
this.client = nextContext.client;
}
this.unsubscribeFromQuery();
this.queryObservable = null;
this.previousData = {};
Expand Down
81 changes: 81 additions & 0 deletions test/react-web/client/graphql/client-option.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/// <reference types="jest" />

import * as React from 'react';
import * as PropTypes from 'prop-types';
import * as ReactDOM from 'react-dom';
import * as renderer from 'react-test-renderer';
import { mount, shallow } from 'enzyme';
import gql from 'graphql-tag';
import ApolloClient, { ApolloError, ObservableQuery } from 'apollo-client';
import { mockNetworkInterface } from '../../../../src/test-utils';
import { ApolloProvider, graphql} from '../../../../src';

describe('client option', () => {

it('renders with client from options', () => {
const query = gql`query people { allPeople(first: 1) { people { name } } }`;
const data = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } };
const networkInterface = mockNetworkInterface({ request: { query }, result: { data } });
const client = new ApolloClient({ networkInterface, addTypename: false });
const config = {
options: {
client,
}
};
const ContainerWithData = graphql(query, config)((props) => null);
shallow(<ContainerWithData />);
});

it('ignores client from context if client from options is present', (done) => {
const query = gql`query people { allPeople(first: 1) { people { name } } }`;
const dataProvider = { allPeople: { people: [ { name: 'Leia Organa Solo' } ] } };
const networkInterfaceProvider = mockNetworkInterface({ request: { query }, result: { data: dataProvider } });
const clientProvider = new ApolloClient({ networkInterface: networkInterfaceProvider, addTypename: false });
const dataOptions = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } };
const networkInterfaceOptions = mockNetworkInterface({ request: { query }, result: { data: dataOptions } });
const clientOptions = new ApolloClient({ networkInterface: networkInterfaceOptions, addTypename: false });

const config = {
options: {
client: clientOptions,
}
};

class Container extends React.Component<any, any> {
componentWillReceiveProps({ data }) { // tslint:disable-line
expect(data.loading).toBe(false); // first data
expect(data.allPeople).toMatchObject({ people: [ { name: 'Luke Skywalker' } ] });
done();
}
render() {
return null;
}
};
const ContainerWithData = graphql(query, config)(Container);
renderer.create(<ApolloProvider client={clientProvider}><ContainerWithData /></ApolloProvider>);

});
it('exposes refetch as part of the props api', (done) => {
const query = gql`query people($first: Int) { allPeople(first: $first) { people { name } } }`;
const variables = { first: 1 };
const data1 = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } };
const networkInterface = mockNetworkInterface(
{ request: { query, variables }, result: { data: data1 } },
);
const client = new ApolloClient({ networkInterface, addTypename: false });

let hasRefetched, count = 0;
@graphql(query)
class Container extends React.Component<any, any> {
componentWillReceiveProps({ data }) { // tslint:disable-line
expect(data.loading).toBe(false); // first data
done();
}
render() {
return null;
}
};

renderer.create(<ApolloProvider client={client}><Container first={1} /></ApolloProvider>);
});
});
4 changes: 2 additions & 2 deletions test/react-web/client/graphql/queries/skip.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ describe('[queries] skip', () => {
renderer.create(<ApolloProvider client={client}><Parent /></ApolloProvider>);
});

it('doesn\'t run options or props when skipped', (done) => {
it('doesn\'t run options or props when skipped, except option.client', (done) => {
const query = gql`query people { allPeople(first: 1) { people { name } } }`;
const data = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } };
const networkInterface = mockNetworkInterface({ request: { query }, result: { data } });
Expand All @@ -132,7 +132,7 @@ describe('[queries] skip', () => {
let queryExecuted;
@graphql(query, {
skip: ({ skip }) => skip,
options: ({ willThrowIfAccesed }) => ({ pollInterval: willThrowIfAccesed.pollInterval }),
options: ({ client, ...willThrowIfAccesed }) => ({ pollInterval: willThrowIfAccesed.pollInterval }),
props: ({ willThrowIfAccesed }) => ({ pollInterval: willThrowIfAccesed.pollInterval }),
})
class Container extends React.Component<any, any> {
Expand Down

0 comments on commit 23d131a

Please sign in to comment.