-
Notifications
You must be signed in to change notification settings - Fork 787
Conversation
What's this and why it's needed? |
@Vanuan that is an option for each query that tells react-apollo to actually fetch the data during rendering on the server |
What's |
I mean, why can't it be true by default? |
So it means that some queries aren't meant to be executed during ssr? |
I believe, the most flexible API would be like this: import { getQueries, runQueries } from "react-apollo"
let queries = getQueries(app, /* props to be pased as ownProps */);
/*
filter out queries you don't want on server side
according to routing or some other logic
*/
queries = ...
runQueries(queries).then((data) => {
// in redux you dispatch query action
// store.dispatch(querySucceeded({data}));
// or update the store somehow else
// fetched data is saved in the store
// in plain React, you'd just provide data to properties
// or use Apollo's store
const markup = ReactDOM.renderToString(app);
// Provider provides stored state to connected components during rendering
}, (err) => {
// dispatch and render errors
}); Of course, dispatching can be hidden inside apollo, but it would be hard to follow and unclear whether it's dispatched or not. |
return queries; | ||
} | ||
|
||
const rawQueries = getQueriesFromTree(tree); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be much more flexible if getQueriesFromTree
is exported
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Vanuan I think we would export it for sure once it is working correctly 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think exporting a few options to allow you to build your own rendering process, or just use react-apollo would be best:
i.e:
getQueries, runQueries
for a fully custom solutiongetData
which runs all queries tagged as SSR- a
renderWithData
that returns back the full SSR payload with the initial state injected into the markup.
@Vanuan this is still very much a WIP |
export function getPropsFromChild(child, defaultProps = {}) { | ||
const { props, type } = child; | ||
let ownProps = assign(defaultProps, props); | ||
if (type && type.defaultProps) ownProps = assign(defaultProps, type.defaultProps, props); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this how react does it internally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pretty much yes, if I'm reading this correctly: https://github.com/facebook/react/blob/49238b944046abf086ba80ab5e984ce8a8175a1d/src/isomorphic/classic/element/ReactElement.js#L207-L214
This could use a lot more testing for sure, but I'm going to cut a release so we can start trying it out in some applications. I've added tests for a few tree structures ranging from simple to mildly complex with mixed classes and components. |
@jbaxleyiii Awesome work. I can give it a try 👍 |
@gauravtiwari 🎉 thanks so much! I'd use the 0.3.17 version (has a bug fix) |
@jbaxleyiii I gave it a try and it seems that I am missing something. Could you a post a minimal setup example for SSR - including component and all (both client and on server) ? import React, from 'react';
import { connect } from 'react-apollo';
const SomeComponent = (props) => {
const { data } = props;
return (
<div className="nav">
something to render
</div>
);
}
function mapQueriesToProps({ ownProps, state }) {
return {
data: `{ someQuery }`
};
};
const SomeComponentWithData = connect({
mapQueriesToProps,
})(SomeComponent);
export default SomeComponentWithData; // Where to pass initial state or props?
const htmlResult = await renderToStringWithData(SomeComponentWithData); Is it possible to just use server to hydrate the store on server and then pass it on to client after render? ( Like react default server side rendering. It renders the component on server and then when the client detects the component it binds all component events etc. ) |
Hey @jbaxleyiii -- worked great for me in this commit: https://github.com/apollostack/saturn/commit/9943e3b72e625bf70efc76f594ca4f0de8c4bef9 for an app which did SSR without queries on the server. However, for githunt, it just hangs: https://github.com/apollostack/GitHunt/tree/saturn-ssr I see some output from (I'm guessing)
|
Hey @jbaxleyiii So, I tried again and it seems that, for NON-JS environment this won't work (unless the JS environment supports callbacks). The response returned is always empty as the server doesn't wait for callback to be finished. |
@tmeasday I've seen it hang every so often for my stuff locally too. I'll be working on that today / tomorrow but would love some help if you can spare! @gauravtiwari ah that makes sense! I need to find a way to make the getData sync for a lot of js use cases anyway. Would it work for you then? |
@jbaxleyiii I'd love to help although I'm not sure I'll have too much time today. I would say that for githunt it consistently, rather than occassionally hangs. Ping me on slack if I can help though. |
@jbaxleyiii Ok, I couldn't help myself. There are two problems that are causing the issue, when I hack around them, it works great!:
The reason is that (yay, thanks npm!) I end up with 2 copies of So it actually works if you run my Oh, and as an aside on deeper calls to I'm not sure what the best solution is. One option is to just not check the type :/ [1] In short npm is terrible at helping you with this problem. I could rant for a while about it. |
@tmeasday this is awesome! I can fix those! |
@jbaxleyiii Yeah, I think so, because rendering react component normally on the server works and returns the response so, as long as the response from |
let fieldsToNotShip = ['minimizedQuery', 'minimizedQueryString']; | ||
for (let field of fieldsToNotShip) delete initialState[key].queries[queryId][field]; | ||
} | ||
initialState = encodeURI(JSON.stringify(initialState)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume encodeURI is wrong? It'll result in
Uncaught SyntaxError: Unexpected token %
Hey guys, anyone had any luck doing this with Meteor? |
active work on #54
The client does have the option to ignore SSR for particular queries
getDataFromTree
The
getDataFromTree
method takes your react tree and returns an object withinitialState
, the apollo client (asclient
) and the redux store asstore
.initialState
is the hydrated data of your redux store prior to app rendering. EitherinitialState
orstore.getState()
can be used for server side rehydration.renderToStringWithData
The
renderToStringWithData
takes your react tree and returns a promise that resolves to your stringified tree with all data requirements. It also injects a script tag that includeswindow. __APOLLO_STATE__
which equals the full redux store for hyrdration.Server notes:
When creating the client on the server, it is best to use
ssrMode: true
. This prevents unneeded force refetching in the tree walking.Client notes:
When creating new client, you can pass
initialState: __APOLLO_STATE__
to rehydrate which will stop the client from trying to requery data.@stubailo @tmeasday this needs more tests, but I thinks its pretty close