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

Commit

Permalink
fix missing redux integration for ssr (#103)
Browse files Browse the repository at this point in the history
* fix missing redux integration for ssr
  • Loading branch information
James Baxley authored Jul 12, 2016
1 parent 2847115 commit 7490b53
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 29 deletions.
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

0 comments on commit 7490b53

Please sign in to comment.