diff --git a/Changelog.md b/Changelog.md index 50d5f636d2..534c2e4d67 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,11 @@ instance in `client`, and the received subscription data in `subscriptionData`.
[@jedwards1211](https://github.com/jedwards1211) in [#1966](https://github.com/apollographql/react-apollo/pull/1966) +- The `graphql` `options` object is no longer mutated, when calculating + variables from props. This now prevents an issue where components created + with `graphql` were not having their query variables updated properly, when + props changed. + [@ksmth](https://github.com/ksmth) in [#1968](https://github.com/apollographql/react-apollo/pull/1968) ## 2.1.11 (August 9, 2018) diff --git a/src/query-hoc.tsx b/src/query-hoc.tsx index 6f7badaa2a..832b38a718 100644 --- a/src/query-hoc.tsx +++ b/src/query-hoc.tsx @@ -33,10 +33,14 @@ export function query< } = operationOptions; let mapPropsToOptions = options as (props: any) => QueryOpts; - if (typeof mapPropsToOptions !== 'function') mapPropsToOptions = () => options as QueryOpts; + if (typeof mapPropsToOptions !== 'function') { + mapPropsToOptions = () => options as QueryOpts; + } let mapPropsToSkip = skip as (props: any) => boolean; - if (typeof mapPropsToSkip !== 'function') mapPropsToSkip = () => skip as any; + if (typeof mapPropsToSkip !== 'function') { + mapPropsToSkip = () => skip as any; + } // allow for advanced referential equality checks let lastResultProps: TChildProps | void; @@ -51,7 +55,7 @@ export function query< render() { let props = this.props; const shouldSkip = mapPropsToSkip(props); - const opts = shouldSkip ? Object.create(null) : mapPropsToOptions(props); + const opts = shouldSkip ? Object.create(null) : { ...mapPropsToOptions(props) }; if (!shouldSkip && !opts.variables && operation.variables.length > 0) { opts.variables = calculateVariablesFromProps( diff --git a/test/client/graphql/queries/index.test.tsx b/test/client/graphql/queries/index.test.tsx index e8cd163f84..637dfcc287 100644 --- a/test/client/graphql/queries/index.test.tsx +++ b/test/client/graphql/queries/index.test.tsx @@ -7,6 +7,7 @@ import { InMemoryCache as Cache } from 'apollo-cache-inmemory'; import { ApolloLink } from 'apollo-link'; import { mockSingleLink } from '../../../../src/test-utils'; import { ApolloProvider, graphql, DataProps, ChildProps } from '../../../../src'; +import { mount } from 'enzyme'; import stripSymbols from '../../../test-utils/stripSymbols'; import catchAsyncError from '../../../test-utils/catchAsyncError'; @@ -112,6 +113,72 @@ describe('queries', () => { ); }); + it('should update query variables when props change', () => { + const query: DocumentNode = gql` + query people($someId: ID) { + allPeople(someId: $someId) { + people { + name + } + } + } + `; + + const link = mockSingleLink( + { + request: { query, variables: { someId: 1 } }, + result: { data: { allPeople: { people: [{ name: 'Luke Skywalker' }] } } }, + }, + { + request: { query, variables: { someId: 2 } }, + result: { data: { allPeople: { people: [{ name: 'Darth Vader' }] } } }, + }, + ); + const client = new ApolloClient({ + link, + cache: new Cache({ addTypename: false }), + }); + + interface Data { + allPeople: { + people: { + name: string; + }; + }; + } + + interface Variables { + someId: number; + } + + const options = { + options: {}, + }; + + let count = 0; + const ContainerWithData = graphql(query, options)( + ({ data }: ChildProps) => { + expect(data).toBeTruthy(); + if (count === 0) { + expect(data!.variables.someId).toEqual(1); + } else if (count === 1) { + expect(data!.variables.someId).toEqual(2); + } + count += 1; + return null; + }, + ); + + const wrapper = mount( + + + , + ); + wrapper.setProps({ + children: React.cloneElement(wrapper.props().children, { someId: 2 }), + }); + }); + it("shouldn't warn about fragments", () => { const oldWarn = console.warn; const warnings: any[] = [];