Skip to content

Commit

Permalink
Server rendering for Apollo.
Browse files Browse the repository at this point in the history
  • Loading branch information
khayong committed Jul 16, 2017
1 parent 877f434 commit f06291c
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 158 deletions.
30 changes: 15 additions & 15 deletions lib/combineReducerWithApollo.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
"use strict";

const combineReducerWithApollo = (reducer, client, key = "apollo") => {
const apolloReducer = client.reducer();
const apolloReducer = client.reducer();

return function combination(state = {}, action) {
// Remove appolo key to prevent unexpected key warning.
const apolloState = state[key];
delete state[key];
return function combination (state = {}, action) {
// Remove appolo key to prevent unexpected key warning.
const apolloState = state[key];
delete state[key];

const nextState = reducer(state, action);
const nextState = reducer(state, action);

const previousStateForApollo = apolloState;
const nextStateForApollo = apolloReducer(previousStateForApollo, action);
const previousStateForApollo = apolloState;
const nextStateForApollo = apolloReducer(previousStateForApollo, action);

if (previousStateForApollo !== nextStateForApollo) {
return Object.assign({}, nextState, {[key]: nextStateForApollo});
} else {
nextState[key] = previousStateForApollo;
return nextState;
}
};
if (previousStateForApollo !== nextStateForApollo) {
return Object.assign({}, nextState, {[key]: nextStateForApollo});
} else {
nextState[key] = previousStateForApollo;
return nextState;
}
};
};

module.exports = combineReducerWithApollo;
52 changes: 30 additions & 22 deletions lib/renderToString.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";

require("isomorphic-fetch");
const assert = require("assert");
const optionalRequire = require("optional-require")(require);
const React = optionalRequire("react");
Expand All @@ -9,31 +10,38 @@ const ReactRouter = require("react-router");
const Provider = require("react-redux").Provider;

const renderToString = (req, store, match, withIds) => { // eslint-disable-line
if (req.app && req.app.disableSSR) {
return "";
} else {
assert(React, "Can't do SSR because React module is not available");
assert(ReactDomServer, "Can't do SSR because ReactDomServer module is not available");
if (req.app && req.app.disableSSR) {
return "";
} else {
assert(React, "Can\'t do SSR because React module is not available");
assert(ReactDomServer,
"Can\'t do SSR because ReactDomServer module is not available");

const app = req.server && req.server.app || req.app;
if (app.apollo) {
assert(ReactApollo, "Can't use Apollo because ReactApollo module is not available");
const app = req.server && req.server.app || req.app;
if (app.apollo) {
assert(ReactApollo,
"Can\'t use Apollo because ReactApollo module is not available");

return (withIds ? ReactDomServer.renderToString : ReactDomServer.renderToStaticMarkup)(
React.createElement(
ReactApollo.ApolloProvider, { store, client: app.apollo },
React.createElement(ReactRouter.RouterContext, match.renderProps)
)
);
} else {
return (withIds ? ReactDomServer.renderToString : ReactDomServer.renderToStaticMarkup)(
React.createElement(
Provider, { store },
React.createElement(ReactRouter.RouterContext, match.renderProps)
)
);
}
const element = React.createElement(
ReactApollo.ApolloProvider, {store, client: app.apollo},
React.createElement(ReactRouter.RouterContext, match.renderProps)
);
return ReactApollo.getDataFromTree(element).then(() => {
return (withIds
? ReactDomServer.renderToString
: ReactDomServer.renderToStaticMarkup)(element);
});
} else {
return (withIds
? ReactDomServer.renderToString
: ReactDomServer.renderToStaticMarkup)(
React.createElement(
Provider, {store},
React.createElement(ReactRouter.RouterContext, match.renderProps)
)
);
}
}
};

module.exports = renderToString;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "electrode-apollo-redux-engine",
"version": "1.0.3",
"version": "1.0.4",
"description": "Integrating Electrode with Apollo and Redux",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -35,6 +35,7 @@
"redux": "^3.7.2"
},
"dependencies": {
"isomorphic-fetch": "^2.2.1",
"optional-require": "^1.0.0",
"react-redux": "^5.0.5",
"react-router": "^3.0.5"
Expand Down
94 changes: 51 additions & 43 deletions test/spec/combine.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,69 @@

const createStore = require("redux").createStore;
const combineReducers = require("redux").combineReducers;
const applyMiddleware = require("redux").applyMiddleware;
const compose = require("redux").compose;
const ApolloClient = require("react-apollo").ApolloClient;

const {combineReducerWithApollo} = require("../..");

const checkBox = (store, action) => {
if (action.type === "TOGGLE_CHECK") {
return {
checked: !store.checked
};
}
if (action.type === "TOGGLE_CHECK") {
return {
checked: !store.checked
};
}

return store || {checked: false};
return store || {checked: false};
};

const number = (store, action) => {
if (action.type === "INC_NUMBER") {
return {
value: store.value + 1
};
} else if (action.type === "DEC_NUMBER") {
return {
value: store.value - 1
};
}

return store || {value: 0};
if (action.type === "INC_NUMBER") {
return {
value: store.value + 1
};
} else if (action.type === "DEC_NUMBER") {
return {
value: store.value - 1
};
}

return store || {value: 0};
};

describe("Combine reducer with Apollo", function () {

it("should combine existing root reducer", () => {
const client = new ApolloClient();

const rootReducer = combineReducers({
checkBox,
number
});

const initialState = {
checkBox: {checked: false},
number: {value: 999}
};
const store = createStore(combineReducerWithApollo(rootReducer, client), initialState);
expect(store.getState()).to.have.all.keys("checkBox", "number", "apollo");
expect(store.getState().checkBox).to.deep.equal({checked: false});
expect(store.getState().number).to.deep.equal({value: 999});

store.dispatch({type: "TOGGLE_CHECK"});
expect(store.getState().checkBox).to.deep.equal({checked: true});
store.dispatch({type: "TOGGLE_CHECK"});
expect(store.getState().checkBox).to.deep.equal({checked: false});

store.dispatch({type: "INC_NUMBER"});
expect(store.getState().number).to.deep.equal({value: 1000});
store.dispatch({type: "DEC_NUMBER"});
expect(store.getState().number).to.deep.equal({value: 999});
it("should combine existing root reducer", () => {
const client = new ApolloClient();

const rootReducer = combineReducers({
checkBox,
number
});

const initialState = {
checkBox: {checked: false},
number: {value: 999}
};
const store = createStore(
combineReducerWithApollo(rootReducer, client),
initialState,
compose(
applyMiddleware(client.middleware())
)
);
expect(store.getState()).to.have.all.keys("checkBox", "number", "apollo");
expect(store.getState().checkBox).to.deep.equal({checked: false});
expect(store.getState().number).to.deep.equal({value: 999});

store.dispatch({type: "TOGGLE_CHECK"});
expect(store.getState().checkBox).to.deep.equal({checked: true});
store.dispatch({type: "TOGGLE_CHECK"});
expect(store.getState().checkBox).to.deep.equal({checked: false});

store.dispatch({type: "INC_NUMBER"});
expect(store.getState().number).to.deep.equal({value: 1000});
store.dispatch({type: "DEC_NUMBER"});
expect(store.getState().number).to.deep.equal({value: 999});
});
});
Loading

0 comments on commit f06291c

Please sign in to comment.