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

Commit

Permalink
Fix SSR with mutations, fix mixing initial props methods, allow objec…
Browse files Browse the repository at this point in the history
…t for options (#145)

* fix ssr oddity (why does this work?) and fix missing methods on initial mount

* allow options to be an object

* version bump
  • Loading branch information
James Baxley authored Aug 16, 2016
1 parent 7c5980a commit f0da04f
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 11 deletions.
5 changes: 5 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

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.4.5

- Feature: Allow options value to be an object instead of a method. [#144](https://github.com/apollostack/react-apollo/issues/144)
- Bug: Fixed issue with missing methods on initial props [#142](https://github.com/apollostack/react-apollo/issues/142)
- Bug: Fixed oddity with multi nested enhancers on SSR [#141](https://github.com/apollostack/react-apollo/issues/141)

### v0.4.4

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-apollo",
"version": "0.4.4",
"version": "0.4.5",
"description": "React data container for Apollo Client",
"main": "index.js",
"scripts": {
Expand Down
27 changes: 22 additions & 5 deletions src/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function withApollo(WrappedComponent) {
};

export interface OperationOption {
options?: (props: any) => QueryOptions | MutationOptions;
options?: Object | ((props: any) => QueryOptions | MutationOptions);
props?: (props: any) => any;
name?: string;
withRef?: boolean;
Expand All @@ -140,7 +140,9 @@ export default function graphql(

// extract options
const { options = defaultMapPropsToOptions } = operationOptions;
const mapPropsToOptions = options;
let mapPropsToOptions = options as (props: any) => QueryOptions | MutationOptions;
if (typeof mapPropsToOptions !== 'function') mapPropsToOptions = () => options;

const mapResultToProps = operationOptions.props;

// safety check on the operation
Expand Down Expand Up @@ -217,8 +219,6 @@ export default function graphql(
store: PropTypes.object.isRequired,
client: PropTypes.object.isRequired,
};
// for use with getData during SSR
static fetchData = operation.type === DocumentType.Query ? fetchData : false;

// start of query composition
static fragments: FragmentDefinition[] = operation.fragments;
Expand Down Expand Up @@ -328,7 +328,22 @@ export default function graphql(
query: document,
variables,
});
queryData = assign({ errors: null, loading: false, variables }, result);

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;
Expand Down Expand Up @@ -553,6 +568,8 @@ export default function graphql(
}
}

if (operation.type === DocumentType.Query) (GraphQL as any).fetchData = fetchData;

// Make sure we preserve any custom statics on the original component.
return hoistNonReactStatics(GraphQL, WrappedComponent);

Expand Down
2 changes: 1 addition & 1 deletion test/react-web/client/graphql/fragments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ describe('fragments', () => {
const client = new ApolloClient({ networkInterface });

@graphql(query, {
options: () => ({ fragments: [shipFragment]})
options: () => ({ fragments: [shipFragment]}),
})
class Container extends React.Component<any, any> {
componentWillReceiveProps(props) {
Expand Down
8 changes: 8 additions & 0 deletions test/react-web/client/graphql/queries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,10 @@ describe('queries', () => {
let hasRefetched;
@graphql(query)
class Container extends React.Component<any, any> {
componentWillMount(){
expect(this.props.data.refetch).to.be.exist;
expect(this.props.data.refetch).to.be.instanceof(Function);
}
componentWillReceiveProps({ data }) { // tslint:disable-line
if (hasRefetched) return;
hasRefetched = true;
Expand Down Expand Up @@ -531,6 +535,10 @@ describe('queries', () => {
let count = 0;
@graphql(query, { options: () => ({ variables }) })
class Container extends React.Component<any, any> {
componentWillMount(){
expect(this.props.data.fetchMore).to.be.exist;
expect(this.props.data.fetchMore).to.be.instanceof(Function);
}
componentWillReceiveProps(props) {
if (count === 0) {
expect(props.data.fetchMore).to.be.exist;
Expand Down
33 changes: 29 additions & 4 deletions test/react-web/client/graphql/shared-operations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ describe('shared opertations', () => {
const testData = { foo: 'bar' };

class Container extends React.Component<any, any> {
someMethod(){
someMethod() {
return testData;
}

Expand All @@ -167,10 +167,35 @@ describe('shared opertations', () => {

const decorated = TestUtils.findRenderedComponentWithType(tree, Decorated);

expect(() => (decorated as any).someMethod()).to.throw()
expect((decorated as any).getWrappedInstance().someMethod()).to.deep.equal(testData);
expect((decorated as any).refs.wrappedInstance.someMethod()).to.deep.equal(testData);
expect(() => (decorated as any).someMethod()).to.throw();
expect((decorated as any).getWrappedInstance().someMethod()).to.deep.equal(testData);
expect((decorated as any).refs.wrappedInstance.someMethod()).to.deep.equal(testData);

});

it('allows options to take an object', (done) => {
const query = gql`query people { allPeople(first: 1) { people { name } } }`;
const data = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } };
const networkInterface = mockNetworkInterface({ request: { query }, result: { data } });
const client = new ApolloClient({ networkInterface });

let queryExecuted;
@graphql(query, { options: { skip: true } })
class Container extends React.Component<any, any> {
componentWillReceiveProps(props) {
queryExecuted = true;
}
render() {
return null;
}
};

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

setTimeout(() => {
if (!queryExecuted) { done(); return; }
done(new Error('query ran even though skip present'));
}, 25);
});

});
54 changes: 54 additions & 0 deletions test/react-web/server/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,60 @@ describe('SSR', () => {
;
});

it('should correctly handle SSR mutations', (done) => {

const query = gql`{ currentUser { firstName } }`;
const data1 = { currentUser: { firstName: 'James' } };

const mutation = gql`mutation { logRoutes { id } }`;
const mutationData= { logRoutes: { id: 'foo' } };

const networkInterface = mockNetworkInterface(
{ request: { query }, result: { data: data1 }, delay: 5 },
{ request: { query: mutation }, result: { data: mutationData }, delay: 5 }
);
const apolloClient = new ApolloClient({ networkInterface });

const withQuery = graphql(query, {
options: (ownProps) => ({ ssr: true }),
props: ({ data }) => {
expect(data.refetch).to.exist;
return {
refetchQuery: data.refetch,
data,
};
},
});

const withMutation = graphql(mutation, {
props: ({ ownProps, mutate }) => {
expect(ownProps.refetchQuery).to.exist;
return {
action(variables) {
return mutate({ variables }).then(() => ownProps.refetchQuery());
},
};
},
});

const Element = (({ data }) => (
<div>{data.loading ? 'loading' : data.currentUser.firstName}</div>
));

const WrappedElement = withQuery(withMutation(Element));

const app = (<ApolloProvider client={apolloClient}><WrappedElement /></ApolloProvider>);

getDataFromTree(app)
.then(() => {
const markup = ReactDOM.renderToString(app);
expect(markup).to.match(/James/);
done();
})
.catch(console.error)
;
});

});

describe('`renderToStringWithData`', () => {
Expand Down

0 comments on commit f0da04f

Please sign in to comment.