📜 ⬆️ ⬇️

Apollo graphql client - development of isomorphic (universal) applications on react.js

In the previous post, the Apollo graphql client was used to develop a purely client application. The Apollo graphql client documentation has a (very concise) section on server rendering and isomorphic applications.

One of the challenges of server-side rendering in react.js is the need for asynchronous data loading, since server rendering in rea.t.js is a synchronous operation. For example, the framework next.js suggests using a special component page for this, in which the additional static async getInitialProps() method static async getInitialProps() implemented, in which it is proposed to perform asynchronous data loading. Such a solution is not without flaws. For example, this method is static, therefore it does not have access to the component instance, the method is implemented only for the component of the highest level and is missing for the nested components. The solution with the Apollo graphql client can be used for a component of an arbitrary level of nesting.

We will continue work with the project which was considered in the previous message . There are two key points in the server code: using the ApolloProvider client={client} component as the root element and asynchronous data retrieval using the await getDataFromTree(App) function. Behind the scenes, ApolloProvider determines which queries need to be made to render components, taking into account the selected route, executes these queries and transfers data to the components when rendering.

 ... import AppRouter from './AppRouter'; import assets from '../build/asset-manifest.json'; module.exports = async (req, res, next) => { const client = new ApolloClient({ ssrMode: true, link: createHttpLink({ uri: 'https://api.graph.cool/simple/v1/ciyz901en4j590185wkmexyex', headers: { cookie: req.header('Cookie'), }, fetch, }), cache: new InMemoryCache(), }); const context = {}; const App = <ApolloProvider client={client}> <StaticRouter location={req.url} context={context}> <AppRouter /> </StaticRouter> </ApolloProvider>; await getDataFromTree(App) const html = ReactDOMServer.renderToString((App)); const initialState = client.extract(); res.write(` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Conduit</title> <link rel="stylesheet" href="/${assets['main.css']}"> </head> <body> <script> // WARNING: See the following for security issues around embedding JSON in HTML: // http://redux.js.org/docs/recipes/ServerRendering.html#security-considerations window.__APOLLO_STATE__ = ${JSON.stringify(initialState, null, 2).replace(/</g, '\\u003c')}; </script> <div id="app">${html}</div> <script src="/${assets['main.js']}"></script> </body> </html> `); res.end(); } 

')
Accordingly, to restore data on the client, you must restore the client state by passing the parameter to the client constructor: cache: new InMemoryCache().restore(window.__APOLLO_STATE__) .

 import App from './App'; import { ApolloClient } from 'apollo-client'; import { HttpLink } from 'apollo-link-http'; import { onError } from 'apollo-link-error'; import { ApolloLink } from 'apollo-link'; import { InMemoryCache } from "apollo-cache-inmemory"; const client = new ApolloClient({ link: ApolloLink.from([ onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) graphQLErrors.map(({ message, locations, path }) => console.log( `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`, ), ); if (networkError) console.log(`[Network error]: ${networkError}`); }), new HttpLink({ uri: 'https://api.graph.cool/simple/v1/ciyz901en4j590185wkmexyex', // credentials: 'same-origin' }) ]), cache: new InMemoryCache().restore(window.__APOLLO_STATE__), }); hydrate(<App client={client} />, document.getElementById('app')); 


I put the code for this example in the ssr repository branch.

Thus, the implementation of server-side rendering and universal applications using the Apollo graphql client is very laconic and differs little from the implementation of a purely client-side rendering. If the grqphql API is implemented on the same server where SSR is implemented, it is possible to avoid API requests through the network (as universal applications almost always do) and request the necessary grqphql functions by calling them directly within node.js.

apapacy@gmail.com
May 20, 2018.

Source: https://habr.com/ru/post/358942/


All Articles