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

Commit

Permalink
Merge a725cfc into e398974
Browse files Browse the repository at this point in the history
  • Loading branch information
James Baxley committed Aug 22, 2016
2 parents e398974 + a725cfc commit e71e3f1
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 44 deletions.
4 changes: 4 additions & 0 deletions Changelog.md
Expand Up @@ -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.

### vNext

- Bug: Fixed loading state on remount of forceFetch operations; [#161](https://github.com/apollostack/react-apollo/pull/161)

### v0.4.6

- Bug: Fixed issue with variable merging after fetchMore [#150](https://github.com/apollostack/react-apollo/pull/150)
Expand Down
82 changes: 38 additions & 44 deletions src/graphql.tsx
Expand Up @@ -62,6 +62,7 @@ export declare interface MutationOptions {
fragments?: FragmentDefinition[] | FragmentDefinition[][];
optimisticResponse?: Object;
updateQueries?: MutationQueryReducersMap;
forceFetch?: boolean;
}

export declare interface QueryOptions {
Expand Down Expand Up @@ -164,9 +165,14 @@ export default function graphql(
}
}

function calculateVariables(props) {
const opts = mapPropsToOptions(props);
if (opts.variables || !operation.variables.length) return opts.variables;
function calculateOptions(props, newOpts?) {
let opts = mapPropsToOptions(props);

if (newOpts && newOpts.variables) {
newOpts.variables = assign({}, opts.variables, newOpts.variables);
}
if (newOpts) opts = assign({}, opts, newOpts);
if (opts.variables || !operation.variables.length) return opts;

let variables = {};
for (let { variable } of operation.variables) {
Expand All @@ -183,17 +189,16 @@ export default function graphql(
`passed to '${graphQLDisplayName}'`
);
}

return variables;
opts.variables = variables;
return opts;
}

function fetchData(props, { client }) {
if (operation.type === DocumentType.Mutation) return false;
const opts = mapPropsToOptions(props) as any;
const opts = calculateOptions(props) as any;
opts.query = document;

if (opts.ssr === false) return false;
if (!opts.variables) opts.variables = calculateVariables(props);
if (!opts.variables) delete opts.variables;
calculateFragments(opts);

Expand Down Expand Up @@ -300,7 +305,7 @@ export default function graphql(
this.hasMounted = false;
}

calculateVariables(props) { return calculateVariables(props); };
calculateOptions(props, newProps?) { return calculateOptions(props, newProps); };

calculateResultProps(result) {
let name = this.type === DocumentType.Query ? 'data' : 'mutate';
Expand All @@ -319,44 +324,43 @@ export default function graphql(
}

const { reduxRootKey } = this.client;
const variables = this.calculateVariables(this.props);
const { variables, forceFetch } = this.calculateOptions(this.props);
let queryData = defaultQueryData as any;
queryData.variables = variables;
try {
const result = readQueryFromStore({
store: this.store.getState()[reduxRootKey].data,
query: document,
variables,
});

const refetch = (vars) => {
return this.client.query({
if (!forceFetch) {
try {
const result = readQueryFromStore({
store: this.store.getState()[reduxRootKey].data,
query: document,
variables: vars,
variables,
});
};

const fetchMore = (opts) => {
opts.query = document;
return this.client.query(opts);
};

queryData = assign({
errors: null, loading: false, variables, refetch, fetchMore,
}, result);
} catch (e) {/* tslint:disable-line */}
const refetch = (vars) => {
return this.client.query({
query: document,
variables: vars,
});
};

const fetchMore = (opts) => {
opts.query = document;
return this.client.query(opts);
};

queryData = assign({
errors: null, loading: false, variables, refetch, fetchMore,
}, result);
} catch (e) {/* tslint:disable-line */}
}

this.data = queryData;
}

subscribeToQuery(props): boolean {
const { watchQuery } = this.client;
const opts = mapPropsToOptions(props) as QueryOptions;
const opts = calculateOptions(props) as QueryOptions;
if (opts.skip) return;

// handle auto merging of variables from props
opts.variables = this.calculateVariables(props);

// don't rerun if nothing has changed
if (isEqual(opts, this.previousOpts)) return false;

Expand Down Expand Up @@ -522,19 +526,9 @@ export default function graphql(
createWrappedMutation(props: any, reRender = false) {
if (this.type !== DocumentType.Mutation) return;

// XXX do we want to do any loading state stuff here?
this.data = (opts: MutationOptions) => {
const original = mapPropsToOptions(props);
opts = this.calculateOptions(props, opts);

// merge variables
if (original.variables) {
original.variables = assign({}, original.variables, opts.variables);
}

opts = assign({}, original, opts);
if (!original.variables && !opts.variables) {
opts.variables = this.calculateVariables(props);
}
if (typeof opts.variables === 'undefined') delete opts.variables;

(opts as any).mutation = document;
Expand Down
47 changes: 47 additions & 0 deletions test/react-web/client/graphql/queries.tsx
Expand Up @@ -137,6 +137,53 @@ describe('queries', () => {
wrapper = mount(app);
});

it('correctly sets loading state on remounted forcefetch', (done) => {
const query = gql`query pollingPeople { allPeople(first: 1) { people { name } } }`;
const data = { allPeople: { people: [ { name: 'Darth Skywalker' } ] } };
const networkInterface = mockNetworkInterface(
{ request: { query }, result: { data }, delay: 10, newData: () => ({
data: {
allPeople: { people: [ { name: `Darth Skywalker - ${Math.random()}` } ] },
},
}) }
);
const client = new ApolloClient({ networkInterface });
let wrapper, app, count = 0;

@graphql(query, { options: { forceFetch: true }})
class Container extends React.Component<any, any> {
componentWillMount() {
if (count === 1) {
expect(this.props.data.loading).to.be.true; // on remount
count++;
}
}
componentWillReceiveProps(props) {
if (count === 0) { // has data
wrapper.unmount();
setTimeout(() => {
wrapper = mount(app);
}, 5);
}

if (count === 2) {
// remounted data after fetch
expect(props.data.loading).to.be.false;
expect(props.data.allPeople).to.exist;
done();
}
count++;
}
render() {
return null;
}
};

app = <ProviderMock client={client}><Container /></ProviderMock>;

wrapper = mount(app);
});

it('executes a query with two root fields', (done) => {
const query = gql`query people {
allPeople(first: 1) { people { name } }
Expand Down

0 comments on commit e71e3f1

Please sign in to comment.