Skip to content
This repository was archived by the owner on Apr 13, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
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.

### v0.3.17

- Bug: Fixed but where SSR wouldn't get calculated props from redux actions [#103](https://github.com/apollostack/react-apollo/pull/103)

### v0.3.16

- Feature: integrated SSR [#83](https://github.com/apollostack/react-apollo/pull/83)
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.3.16",
"version": "0.3.17",
"description": "React data container for Apollo Client",
"main": "index.js",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions src/connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export default function connect(opts?: ConnectOptions) {
};
// for use with getData during SSR
static mapQueriesToProps = mapQueries ? mapQueriesToProps : false;
static opts = opts;

// react / redux and react dev tools (HMR) needs
public state: any; // redux state
Expand Down
8 changes: 7 additions & 1 deletion src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,15 @@ function getQueriesFromTree({ component, context = {}, queries = []}: QueryTreeA
if (typeof type === 'function') {
let ComponentClass = type;
let ownProps = getPropsFromChild(component);
const { state } = context;

// see if this is a connect type
if (typeof type.mapQueriesToProps === 'function') {
const state = store.getState();
const { mapStateToProps, mapDispatchToProps, mergeProps } = type.opts;
const mappedState = mapStateToProps && mapStateToProps(state, ownProps);
const mappedDisptach = mapDispatchToProps && mapDispatchToProps(store.dispatch, ownProps);
const mergedProps = mergeProps && mergeProps(mappedState, mappedDisptach, ownProps);
ownProps = assign(ownProps, mappedState, mappedDisptach, mergedProps);
const data = type.mapQueriesToProps({ ownProps, state });
for (let key in data) {
if (!data.hasOwnProperty(key)) continue;
Expand Down Expand Up @@ -150,6 +155,7 @@ export function getDataFromTree(app, ctx: any = {}): Promise<any> {

if (!store && client && !client.store) client.initStore();
if (!store && client && client.store) store = client.store;

// no client found, nothing to do
if (!client || !store) return Promise.resolve(null);

Expand Down
135 changes: 108 additions & 27 deletions test/server/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ApolloClient, { createNetworkInterface } from 'apollo-client';
import { connect, ApolloProvider } from '../../src';
import { getDataFromTree, renderToStringWithData } from '../../src/server';
import 'isomorphic-fetch';
import { createStore, combineReducers, applyMiddleware } from 'redux';

import gql from 'graphql-tag';

Expand Down Expand Up @@ -108,40 +109,21 @@ describe('SSR', () => {
});

it('should run return the initial state for hydration', (done) => {
const Element = ({ data }) => {
return <div>{data.loading ? 'loading' : data.currentUser.firstName}</div>;
};

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

const data = {
currentUser: {
firstName: 'James',
},
};
const query = gql`query App { currentUser { firstName } }`;
const data = { currentUser: { firstName: 'James' } };

const networkInterface = mockNetworkInterface(
{
request: { query },
result: { data },
delay: 50,
}
{ request: { query }, result: { data }, delay: 50 }
);

const apolloClient = new ApolloClient({
networkInterface,
});
const apolloClient = new ApolloClient({ networkInterface });

const WrappedElement = connect({
mapQueriesToProps: () => ({
data: { query },
}),
mapQueriesToProps: () => ({ data: { query } }),
})(Element);

const app = (
Expand All @@ -157,6 +139,105 @@ describe('SSR', () => {
done();
});
});
it('should allow using the calculated props in the mapQueriesToProps function', (done) => {
function counter(state = 0, action) {
return action.type === 'INCREMENT' ? state + 1 : state;
}
const Element = ({ data }) => (
<div>{data.loading ? 'loading' : data.currentUser.firstName}</div>
);

const query = gql`query App($ctnr: Int) { currentUser(ctrn: $ctnr) { firstName } }`;
const data = { currentUser: { firstName: 'James' } };

const networkInterface = mockNetworkInterface(
{ request: { query, variables: { ctnr: 1 } }, result: { data }, delay: 50 }
);

const apolloClient = new ApolloClient({ networkInterface });

function mapStateToProps(state) {
return { ctnr: state.counter + 1 }
}

const WrappedElement = connect({
mapQueriesToProps: ({ ownProps }) => ({
data: { query, variables: { ctnr: ownProps.ctnr } },
}),
mapStateToProps,
})(Element);

// Typscript workaround
const apolloReducer = apolloClient.reducer() as () => any;
const store = createStore(
combineReducers({ counter, apollo: apolloReducer }),
applyMiddleware(apolloClient.middleware())
);

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

getDataFromTree(app)
.then(({ initialState }) => {
expect(initialState.apollo.data).to.exist;
expect(initialState.apollo.data['ROOT_QUERY.currentUser({"ctrn":1})']).to.exist;
done();
})
.catch(done);
});

it('should allow using the state in the mapQueriesToProps function', (done) => {
function counter(state = 0, action) {
return action.type === 'INCREMENT' ? state + 1 : state;
}
const Element = ({ data }) => (
<div>{data.loading ? 'loading' : data.currentUser.firstName}</div>
);

const query = gql`query App($ctnr: Int) { currentUser(ctrn: $ctnr) { firstName } }`;
const data = { currentUser: { firstName: 'James' } };

const networkInterface = mockNetworkInterface(
{ request: { query, variables: { ctnr: 0 } }, result: { data }, delay: 50 }
);

const apolloClient = new ApolloClient({ networkInterface });

function mapStateToProps(state) {
return { ctnr: state.counter + 1 }
}

const WrappedElement = connect({
mapQueriesToProps: ({ state }) => ({
data: { query, variables: { ctnr: state.counter } },
}),
mapStateToProps,
})(Element);

// Typscript workaround
const apolloReducer = apolloClient.reducer() as () => any;
const store = createStore(
combineReducers({ counter, apollo: apolloReducer }),
applyMiddleware(apolloClient.middleware())
);

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

getDataFromTree(app)
.then(({ initialState }) => {
expect(initialState.apollo.data).to.exist;
expect(initialState.apollo.data['ROOT_QUERY.currentUser({"ctrn":0})']).to.exist;
done();
})
.catch(done);
});
it('shouldn\'t run queries if ssr is turned to off', (done) => {
const Element = ({ data }) => {
return <div>{data.loading ? 'loading' : data.currentUser.firstName}</div>;
Expand Down