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

Fix context issues on SSR #165

Merged
merged 3 commits into from
Aug 23, 2016
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
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Expect active development and potentially significant breaking changes in the `0

### vNext

- Bug: Fixed SSR issue with context [#165](https://github.com/apollostack/react-apollo/pull/165)
- Bug: Fixed issue when context changes in parent container not going through to child; [#162](https://github.com/apollostack/react-apollo/pull/162)
- Bug: Fixed loading state on remount of forceFetch operations; [#161](https://github.com/apollostack/react-apollo/pull/161)

Expand Down
12 changes: 8 additions & 4 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ export function getChildFromComponent(component) {
return component;
}

let contextStore = {};
function getQueriesFromTree(
{ component, context = {}, queries = []}: QueryTreeArgument, fetch: boolean = true
) {

contextStore = assign({}, contextStore, context);
if (!component) return;

// stateless function
Expand All @@ -51,8 +52,6 @@ function getQueriesFromTree(
let newContext = context;
if (Component.getChildContext) newContext = assign({}, context, Component.getChildContext());

context = newContext;

// see if there is a fetch data method
if (typeof type.fetchData === 'function' && fetch) {
const query = type.fetchData(ownProps, newContext);
Expand All @@ -72,13 +71,18 @@ function getQueriesFromTree(
}));
}

return { queries, context };
return { queries, context: contextStore };
}

// XXX component Cache
export function getDataFromTree(app, ctx: any = {}, fetch: boolean = true): Promise<any> {

// reset for next loop
contextStore = {};
let { context, queries } = getQueriesFromTree({ component: app, context: ctx }, fetch);
// reset for next loop
contextStore = {};

// no queries found, nothing to do
if (!queries.length) return Promise.resolve(context);

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

it('should not require `ApolloProvider` to be the root component', (done) => {

const query = gql`{ currentUser { firstName } }`;
const data = { currentUser: { firstName: 'James' } };
const networkInterface = mockNetworkInterface(
{ request: { query }, result: { data }, delay: 50 }
);
const apolloClient = new ApolloClient({ networkInterface });

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

class MyRootContainer extends React.Component<any, any> {

constructor(props) {
super(props);
this.state = { color: 'purple' };
}

getChildContext() {
return { color: this.state.color };
}

render() {
return <div>{this.props.children}</div>;
}
}

(MyRootContainer as any).childContextTypes = {
color: React.PropTypes.string,
};

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

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

});

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