diff --git a/Changelog.md b/Changelog.md index e153b3e344..4c57636a56 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,10 @@ Expect active development and potentially significant breaking changes in the `0.x` track. We'll try to be diligent about releasing a `1.0` version in a timely fashion (ideally within 1 or 2 months), so that we can take advantage of SemVer to signify breaking changes from that point on. +### v0.3.11 + +Bug: fixed overrendering of components on redux state changes + ### v0.3.10 Bug: fixed bug where SSR would fail due to later updates. This should also prevent unmounted components from throwing errors. diff --git a/package.json b/package.json index b8b78716dc..aae847ee76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-apollo", - "version": "0.3.10", + "version": "0.3.11", "description": "React data container for Apollo Client", "main": "index.js", "scripts": { @@ -46,6 +46,7 @@ "colors": "^1.1.2", "enzyme": "^2.2.0", "graphql": "^0.5.0", + "graphql-tag": "^0.1.7", "gzip-size": "^3.0.0", "isomorphic-fetch": "^2.2.1", "istanbul": "^0.4.2", diff --git a/src/connect.tsx b/src/connect.tsx index 0a15ecb508..1caf15035a 100644 --- a/src/connect.tsx +++ b/src/connect.tsx @@ -220,15 +220,14 @@ export default function connect(opts?: ConnectOptions) { if (!isEqual(oldState, newState)) { this.previousState = newState; - this.hasOwnStateChanged = true; - this.subscribeToAllQueries(props); + this.hasOwnStateChanged = this.subscribeToAllQueries(props); this.createAllMutationHandles(props); } }); } - subscribeToAllQueries(props: any) { + subscribeToAllQueries(props: any): boolean { const { watchQuery, reduxRootKey } = this.client; const { store } = this; @@ -242,7 +241,7 @@ export default function connect(opts?: ConnectOptions) { // don't re run queries if nothing has changed if (isEqual(oldQueries, queryHandles)) { - return; + return false; } else if (oldQueries) { // unsubscribe from previous queries this.unsubcribeAllQueries(); @@ -284,6 +283,7 @@ export default function connect(opts?: ConnectOptions) { this.handleQueryData(handle, key); } } + return true; } unsubcribeAllQueries() { diff --git a/test/client/connect/mutations.tsx b/test/client/connect/mutations.tsx index b0338c29bd..d6ee7fea5e 100644 --- a/test/client/connect/mutations.tsx +++ b/test/client/connect/mutations.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import * as chai from 'chai'; import { mount } from 'enzyme'; import { createStore, combineReducers, applyMiddleware } from 'redux'; -import gql from 'apollo-client/gql'; +import gql from 'graphql-tag'; // import { spy } from 'sinon'; import ApolloClient from 'apollo-client'; diff --git a/test/client/connect/props.tsx b/test/client/connect/props.tsx index a2cfcbccbd..b850138f1c 100644 --- a/test/client/connect/props.tsx +++ b/test/client/connect/props.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import * as chai from 'chai'; import { mount } from 'enzyme'; import { createStore } from 'redux'; -import gql from 'apollo-client/gql'; +import gql from 'graphql-tag'; import ApolloClient from 'apollo-client'; diff --git a/test/client/connect/queries.tsx b/test/client/connect/queries.tsx index 5dbfe2ff94..2f57eb4b6e 100644 --- a/test/client/connect/queries.tsx +++ b/test/client/connect/queries.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import * as chai from 'chai'; import { mount } from 'enzyme'; import { createStore, combineReducers, applyMiddleware } from 'redux'; -import gql from 'apollo-client/gql'; +import gql from 'graphql-tag'; import ApolloClient from 'apollo-client'; @@ -22,120 +22,6 @@ import { import connect from '../../../src/connect'; describe('queries', () => { - it('doesn\'t rerun the query if it doesn\'t change', (done) => { - const query = gql` - query people($person: Int!) { - allPeople(first: $person) { - people { - name - } - } - } - `; - - const data1 = { - allPeople: { - people: [ - { - name: 'Luke Skywalker', - }, - ], - }, - }; - - const data2 = { - allPeople: { - people: [ - { - name: 'Leia Skywalker', - }, - ], - }, - }; - - const variables1 = { - person: 1 - } - - const variables2 = { - person: 2 - } - - const networkInterface = mockNetworkInterface( - { - request: { query, variables: variables1 }, - result: { data: data1 }, - }, - { - request: { query, variables: variables2 }, - result: { data: data2 }, - } - ); - - const client = new ApolloClient({ - networkInterface, - }); - - function mapQueriesToProps({ state }) { - return { - foobar: { - query, - variables: { - person: 1, - } - }, - }; - }; - - function counter(state = 1, action) { - switch (action.type) { - case 'INCREMENT': - return state + 1 - default: - return state - } - } - - // Typscript workaround - const apolloReducer = client.reducer() as () => any; - - const store = createStore( - combineReducers({ - counter, - apollo: apolloReducer - }), - applyMiddleware(client.middleware()) - ); - - let hasDispatched = false; - let count = 0; - @connect({ mapQueriesToProps }) - class Container extends React.Component { - - componentWillReceiveProps(nextProps) { - count++; - if (nextProps.foobar.allPeople && !hasDispatched) { - hasDispatched = true; - this.props.dispatch({ type: 'INCREMENT' }); - } - } - render() { - return ; - } - }; - - const wrapper = mount( - - - - ); - - setTimeout(() => { - expect(count).to.equal(2); - done(); - }, 250); - }); - it('binds a query to props', () => { const store = createStore(() => ({ foo: 'bar', @@ -347,6 +233,7 @@ describe('queries', () => { } } + let hasFinished; @connect({ mapStateToProps, mapQueriesToProps }) class Container extends React.Component { @@ -355,7 +242,8 @@ describe('queries', () => { } componentWillReceiveProps(nextProps) { - if (!nextProps.people.loading) { + if (!nextProps.people.loading && !hasFinished) { + hasFinished = true; expect(nextProps.ctnr).to.equal(2); done(); } @@ -1925,4 +1813,121 @@ describe('queries', () => { done(); }); }); + + it('doesn\'t rerun the query if it doesn\'t change', (done) => { + const query = gql` + query people($person: Int!) { + allPeople(first: $person) { + people { + name + } + } + } + `; + + const data1 = { + allPeople: { + people: [ + { + name: 'Luke Skywalker', + }, + ], + }, + }; + + const data2 = { + allPeople: { + people: [ + { + name: 'Leia Skywalker', + }, + ], + }, + }; + + const variables1 = { + person: 1 + } + + const variables2 = { + person: 2 + } + + const networkInterface = mockNetworkInterface( + { + request: { query, variables: variables1 }, + result: { data: data1 }, + }, + { + request: { query, variables: variables2 }, + result: { data: data2 }, + } + ); + + const client = new ApolloClient({ + networkInterface, + }); + + function mapQueriesToProps() { + return { + foobar: { + query, + variables: { + person: 1, + } + }, + }; + }; + + function counter(state = 1, action) { + switch (action.type) { + case 'INCREMENT': + return state + 1 + default: + return state + } + } + + // Typscript workaround + const apolloReducer = client.reducer() as () => any; + + const store = createStore( + combineReducers({ + counter, + apollo: apolloReducer + }), + applyMiddleware(client.middleware()) + ); + + let hasDispatched = false; + let localcount = 0; + @connect({ mapQueriesToProps }) + class Container extends React.Component { + + componentWillReceiveProps(nextProps) { + if (nextProps.foobar.allPeople && !hasDispatched) { + hasDispatched = true; + this.props.dispatch({ type: 'INCREMENT' }); + } + } + componentDidUpdate() { + localcount++; + } + + render() { + return ; + } + }; + + const wrapper = mount( + + + + ); + + setTimeout(() => { + expect(localcount).to.equal(2); + done(); + }, 50); + }); }); diff --git a/test/server/index.tsx b/test/server/index.tsx index 2b606ad571..569d887ad0 100644 --- a/test/server/index.tsx +++ b/test/server/index.tsx @@ -6,7 +6,7 @@ import { connect, ApolloProvider } from '../../src'; import 'isomorphic-fetch'; // Globally register gql template literal tag -import gql from 'apollo-client/gql'; +import gql from 'graphql-tag'; const { expect } = chai;