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

Commit

Permalink
limit reruns of queries
Browse files Browse the repository at this point in the history
  • Loading branch information
James Baxley committed May 11, 2016
1 parent 6c3628c commit 3b14705
Show file tree
Hide file tree
Showing 2 changed files with 247 additions and 6 deletions.
16 changes: 12 additions & 4 deletions src/connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export default function connect(opts?: ConnectOptions) {
private client: ApolloClient; // apollo client
private data: Object; // apollo data
private previousState: Object;
private previousQueries: Object;

// request / action storage
private queryHandles: any;
Expand Down Expand Up @@ -184,7 +185,6 @@ export default function connect(opts?: ConnectOptions) {
this.previousState = newState;
this.hasOwnStateChanged = true;

this.unsubcribeAllQueries();
this.subscribeToAllQueries(props);
}
});
Expand All @@ -197,8 +197,6 @@ export default function connect(opts?: ConnectOptions) {
// to avoid rebinding queries if nothing has changed
if (!isEqual(this.props, nextProps)) {
this.haveOwnPropsChanged = true;

this.unsubcribeAllQueries();
this.subscribeToAllQueries(nextProps);
}
}
Expand All @@ -223,12 +221,22 @@ export default function connect(opts?: ConnectOptions) {
const { watchQuery, reduxRootKey } = this.client;
const { store } = this;

// console.log(store.getState())
const queryHandles = mapQueriesToProps({
state: store.getState(),
ownProps: props,
});

const oldQueries = assign({}, this.previousQueries);
this.previousQueries = assign({}, queryHandles);

// don't re run queries if nothing has changed
if (isEqual(oldQueries, queryHandles)) {
return;
} else if (oldQueries) {
// unsubscribe from previous queries
this.unsubcribeAllQueries();
}

if (isObject(queryHandles) && Object.keys(queryHandles).length) {
this.queryHandles = queryHandles;

Expand Down
237 changes: 235 additions & 2 deletions test/connect/queries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,120 @@ 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<any, any> {

componentWillReceiveProps(nextProps) {
count++;
if (nextProps.foobar.allPeople && !hasDispatched) {
hasDispatched = true;
this.props.dispatch({ type: 'INCREMENT' });
}
}
render() {
return <Passthrough {...this.props} />;
}
};

const wrapper = mount(
<ProviderMock store={store} client={client}>
<Container />
</ProviderMock>
);

setTimeout(() => {
expect(count).to.equal(2);
done();
}, 250);
});

it('binds a query to props', () => {
const store = createStore(() => ({
foo: 'bar',
Expand Down Expand Up @@ -116,11 +230,12 @@ describe('queries', () => {
const client = new ApolloClient({
networkInterface,
});

let wrapper;
let firstRun = true;
function mapQueriesToProps({ state }) {
if (!firstRun) {
expect(state.counter).to.equal(2);
wrapper.unmount();
done();
} else {
firstRun = false;
Expand Down Expand Up @@ -156,7 +271,120 @@ describe('queries', () => {
componentWillReceiveProps(nextProps) {
if (nextProps.people.allPeople && !hasDispatched) {
hasDispatched = true;
console.log("dispatching")
this.props.dispatch({ type: 'INCREMENT' });
}
}
render() {
return <Passthrough {...this.props} />;
}
};

wrapper = mount(
<ProviderMock store={store} client={client}>
<Container pass='through' baz={50} />
</ProviderMock>
) as any;

});

it('does rerun the query if it changes', (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,
});

let firstRun = true;
function mapQueriesToProps({ state }) {
return {
people: {
query,
variables: {
person: state.counter,
}
},
};
};

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<any, any> {
componentDidMount(){
count++; // increase for the loading
}

componentWillReceiveProps(nextProps) {
count++;
if (nextProps.people.allPeople && !hasDispatched) {
hasDispatched = true;
this.props.dispatch({ type: 'INCREMENT' });
}
}
Expand All @@ -170,6 +398,11 @@ describe('queries', () => {
<Container pass='through' baz={50} />
</ProviderMock>
);

setTimeout(() => {
expect(count).to.equal(3);
done();
}, 250);
});

it('stops the query after unmounting', () => {
Expand Down

0 comments on commit 3b14705

Please sign in to comment.