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

Commit b75bbbf

Browse files
ksmthhwillson
authored andcommitted
Don't mutate options object when calculating variables from props (#1968)
* Code formatting; Test; Chanelog update
1 parent 8e374f2 commit b75bbbf

File tree

3 files changed

+79
-3
lines changed

3 files changed

+79
-3
lines changed

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
instance in `client`, and the received subscription data in
1111
`subscriptionData`. <br/>
1212
[@jedwards1211](https://github.com/jedwards1211) in [#1966](https://github.com/apollographql/react-apollo/pull/1966)
13+
- The `graphql` `options` object is no longer mutated, when calculating
14+
variables from props. This now prevents an issue where components created
15+
with `graphql` were not having their query variables updated properly, when
16+
props changed.
17+
[@ksmth](https://github.com/ksmth) in [#1968](https://github.com/apollographql/react-apollo/pull/1968)
1318

1419
## 2.1.11 (August 9, 2018)
1520

src/query-hoc.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,14 @@ export function query<
3333
} = operationOptions;
3434

3535
let mapPropsToOptions = options as (props: any) => QueryOpts;
36-
if (typeof mapPropsToOptions !== 'function') mapPropsToOptions = () => options as QueryOpts;
36+
if (typeof mapPropsToOptions !== 'function') {
37+
mapPropsToOptions = () => options as QueryOpts;
38+
}
3739

3840
let mapPropsToSkip = skip as (props: any) => boolean;
39-
if (typeof mapPropsToSkip !== 'function') mapPropsToSkip = () => skip as any;
41+
if (typeof mapPropsToSkip !== 'function') {
42+
mapPropsToSkip = () => skip as any;
43+
}
4044

4145
// allow for advanced referential equality checks
4246
let lastResultProps: TChildProps | void;
@@ -51,7 +55,7 @@ export function query<
5155
render() {
5256
let props = this.props;
5357
const shouldSkip = mapPropsToSkip(props);
54-
const opts = shouldSkip ? Object.create(null) : mapPropsToOptions(props);
58+
const opts = shouldSkip ? Object.create(null) : { ...mapPropsToOptions(props) };
5559

5660
if (!shouldSkip && !opts.variables && operation.variables.length > 0) {
5761
opts.variables = calculateVariablesFromProps(

test/client/graphql/queries/index.test.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { InMemoryCache as Cache } from 'apollo-cache-inmemory';
77
import { ApolloLink } from 'apollo-link';
88
import { mockSingleLink } from '../../../../src/test-utils';
99
import { ApolloProvider, graphql, DataProps, ChildProps } from '../../../../src';
10+
import { mount } from 'enzyme';
1011

1112
import stripSymbols from '../../../test-utils/stripSymbols';
1213
import catchAsyncError from '../../../test-utils/catchAsyncError';
@@ -112,6 +113,72 @@ describe('queries', () => {
112113
);
113114
});
114115

116+
it('should update query variables when props change', () => {
117+
const query: DocumentNode = gql`
118+
query people($someId: ID) {
119+
allPeople(someId: $someId) {
120+
people {
121+
name
122+
}
123+
}
124+
}
125+
`;
126+
127+
const link = mockSingleLink(
128+
{
129+
request: { query, variables: { someId: 1 } },
130+
result: { data: { allPeople: { people: [{ name: 'Luke Skywalker' }] } } },
131+
},
132+
{
133+
request: { query, variables: { someId: 2 } },
134+
result: { data: { allPeople: { people: [{ name: 'Darth Vader' }] } } },
135+
},
136+
);
137+
const client = new ApolloClient({
138+
link,
139+
cache: new Cache({ addTypename: false }),
140+
});
141+
142+
interface Data {
143+
allPeople: {
144+
people: {
145+
name: string;
146+
};
147+
};
148+
}
149+
150+
interface Variables {
151+
someId: number;
152+
}
153+
154+
const options = {
155+
options: {},
156+
};
157+
158+
let count = 0;
159+
const ContainerWithData = graphql<Variables, Data, Variables>(query, options)(
160+
({ data }: ChildProps<Variables, Data, Variables>) => {
161+
expect(data).toBeTruthy();
162+
if (count === 0) {
163+
expect(data!.variables.someId).toEqual(1);
164+
} else if (count === 1) {
165+
expect(data!.variables.someId).toEqual(2);
166+
}
167+
count += 1;
168+
return null;
169+
},
170+
);
171+
172+
const wrapper = mount(
173+
<ApolloProvider client={client}>
174+
<ContainerWithData someId={1} />
175+
</ApolloProvider>,
176+
);
177+
wrapper.setProps({
178+
children: React.cloneElement(wrapper.props().children, { someId: 2 }),
179+
});
180+
});
181+
115182
it("shouldn't warn about fragments", () => {
116183
const oldWarn = console.warn;
117184
const warnings: any[] = [];

0 commit comments

Comments
 (0)