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

Commit

Permalink
configure new skip method in options
Browse files Browse the repository at this point in the history
  • Loading branch information
James Baxley committed Oct 7, 2016
1 parent d53daf3 commit 8d76772
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 6 deletions.
21 changes: 17 additions & 4 deletions src/graphql.tsx
Expand Up @@ -111,7 +111,7 @@ export function withApollo(WrappedComponent) {
export interface OperationOption {
options?: Object | ((props: any) => QueryOptions | MutationOptions);
props?: (props: any) => any;
skip?: (props: any) => boolean;
skip?: boolean | ((props: any) => boolean);
name?: string;
withRef?: boolean;
}
Expand All @@ -122,10 +122,14 @@ export default function graphql(
) {

// extract options
const { options = defaultMapPropsToOptions } = operationOptions;
const { options = defaultMapPropsToOptions, skip = defaultMapPropsToSkip } = operationOptions;

let mapPropsToOptions = options as (props: any) => QueryOptions | MutationOptions;
if (typeof mapPropsToOptions !== 'function') mapPropsToOptions = () => options;

let mapPropsToSkip = skip as (props: any) => boolean;
if (typeof mapPropsToSkip !== 'function') mapPropsToSkip = (() => skip as any);

const mapResultToProps = operationOptions.props;

// safety check on the operation
Expand Down Expand Up @@ -184,6 +188,7 @@ export default function graphql(
}

function fetchData(props, { client }) {
if (mapPropsToSkip(props)) return;
if (operation.type === DocumentType.Mutation) return false;
const opts = calculateOptions(props) as any;
opts.query = document;
Expand Down Expand Up @@ -260,6 +265,7 @@ export default function graphql(
this.queryObservable = {};
this.querySubscription = {};

if (mapPropsToSkip(props)) return;
this.setInitialProps();

}
Expand All @@ -268,11 +274,16 @@ export default function graphql(
this.hasMounted = true;
if (this.type === DocumentType.Mutation) return;

if (mapPropsToSkip(this.props)) return;
this.subscribeToQuery(this.props);

}

componentWillReceiveProps(nextProps) {
// if this has changed, remove data and unsubscribeFromQuery
if (!mapPropsToSkip(this.props) && mapPropsToSkip(nextProps)) {
delete this.data;
return this.unsubscribeFromQuery();
}
if (shallowEqual(this.props, nextProps)) return;

if (this.type === DocumentType.Mutation) {
Expand Down Expand Up @@ -315,7 +326,7 @@ export default function graphql(

const queryOptions = this.calculateOptions(this.props);
const fragments = calculateFragments(queryOptions.fragments);
const { variables, forceFetch, skip } = queryOptions as QueryOptions;
const { variables, forceFetch, skip } = queryOptions as QueryOptions; // tslint:disable-line

let queryData = assign({}, defaultQueryData) as any;
queryData.variables = variables;
Expand Down Expand Up @@ -561,6 +572,8 @@ export default function graphql(
}

render() {
if (mapPropsToSkip(this.props)) return createElement(WrappedComponent, this.props);

const { haveOwnPropsChanged, hasOperationDataChanged, renderedElement, props, data } = this;

this.haveOwnPropsChanged = false;
Expand Down
94 changes: 92 additions & 2 deletions test/react-web/client/graphql/queries-1.test.tsx
Expand Up @@ -407,13 +407,39 @@ describe('queries', () => {
const client = new ApolloClient({ networkInterface });

let queryExecuted;
@graphql(query, { skip: () => true })
@graphql(query, { skip: ({ skip }) => skip })
class Container extends React.Component<any, any> {
componentWillReceiveProps(props) {
queryExecuted = true;
}
render() {
expect(this.props.data).toBeNull();
expect(this.props.data).toBeFalsy();
return null;
}
};

renderer.create(<ProviderMock client={client}><Container skip={true} /></ProviderMock>);

setTimeout(() => {
if (!queryExecuted) { done(); return; }
done(new Error('query ran even though skip present'));
}, 25);
});

it('allows you to skip a query without running it (alternate syntax)', (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 } });
const client = new ApolloClient({ networkInterface });

let queryExecuted;
@graphql(query, { skip: true })
class Container extends React.Component<any, any> {
componentWillReceiveProps(props) {
queryExecuted = true;
}
render() {
expect(this.props.data).toBeFalsy();
return null;
}
};
Expand All @@ -426,6 +452,70 @@ describe('queries', () => {
}, 25);
});

it('removes the injected props if skip becomes true', (done) => {
let count = 0;
const query = gql`
query people($first: Int) {
allPeople(first: $first) { people { name } }
}
`;

const data1 = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } };
const variables1 = { first: 1 };

const data2 = { allPeople: { people: [ { name: 'Leia Skywalker' } ] } };
const variables2 = { first: 2 };

const networkInterface = mockNetworkInterface(
{ request: { query, variables: variables1 }, result: { data: data1 } },
{ request: { query, variables: variables2 }, result: { data: data2 } }
);

const client = new ApolloClient({ networkInterface });

@graphql(query, {
skip: () => count === 1,
options: (props) => ({ variables: props }),
})
class Container extends React.Component<any, any> {
componentWillReceiveProps({ data }) {
// loading is true, but data still there
if (count === 0) expect(data.allPeople).toEqual(data1.allPeople);
if (count === 1 ) expect(data).toBeFalsy();
if (count === 2 && data.loading) expect(data.allPeople).toBeFalsy();
if (count === 2 && !data.loading) {
expect(data.allPeople).toEqual(data2.allPeople);
done();
}
}
render() {
return null;
}
};

class ChangingProps extends React.Component<any, any> {
state = { first: 1 };

componentDidMount() {
setTimeout(() => {
count++;
this.setState({ first: 2 });
}, 50);

setTimeout(() => {
count++;
this.setState({ first: 3 });
}, 100);
}

render() {
return <Container first={this.state.first} />;
}
}

renderer.create(<ProviderMock client={client}><ChangingProps /></ProviderMock>);
});

it('reruns the query if it changes', (done) => {
let count = 0;
const query = gql`
Expand Down
46 changes: 46 additions & 0 deletions test/react-web/server/index.test.tsx
Expand Up @@ -55,6 +55,52 @@ describe('SSR', () => {
;
});

it('should correctly skip queries (deprecated)', () => {

const query = gql`{ currentUser { firstName } }`;
const data = { currentUser: { firstName: 'James' } };
const networkInterface = mockNetworkInterface(
{ request: { query }, result: { data }, delay: 50 }
);
const apolloClient = new ApolloClient({ networkInterface });

const WrappedElement = graphql(query, { options: { skip: true }})(({ data }) => (
<div>{data.loading ? 'loading' : 'skipped'}</div>
));

const app = (<ApolloProvider client={apolloClient}><WrappedElement /></ApolloProvider>);

return getDataFromTree(app)
.then(() => {
const markup = ReactDOM.renderToString(app);
expect(markup).toMatch(/skipped/);
})
;
});

it('should correctly skip queries (deprecated)', () => {

const query = gql`{ currentUser { firstName } }`;
const data = { currentUser: { firstName: 'James' } };
const networkInterface = mockNetworkInterface(
{ request: { query }, result: { data }, delay: 50 }
);
const apolloClient = new ApolloClient({ networkInterface });

const WrappedElement = graphql(query, { skip: true })(({ data }) => (
<div>{!data ? 'skipped' : 'dang'}</div>
));

const app = (<ApolloProvider client={apolloClient}><WrappedElement /></ApolloProvider>);

return getDataFromTree(app)
.then(() => {
const markup = ReactDOM.renderToString(app);
expect(markup).toMatch(/skipped/);
})
;
});

it('should run return the initial state for hydration', () => {
const query = gql`{ currentUser { firstName } }`;
const data = { currentUser: { firstName: 'James' } };
Expand Down

0 comments on commit 8d76772

Please sign in to comment.