Хабрахабр

Apollo graphql client — разработка изоморфных (универсальных) приложений на react.js

В предыдущем сообщении Apollo graphql client применялся для разработки чисто клиентского приложения. В документации Apollo graphql client есть (очень лаконичный) раздел, посвященный серверному рендерингу и изоморфным приложениям.

серверный рендеринг в reaсt.js — операция синхронная. Одна из сложностей серверного рендеринга в react.js является необходимость асинхронной загрузки данных, т.к. Такое решение не лишено недостатков. Например, фреймверк next.js предлагает для этого использовать специальный компонент page в котором реализован дополнительный метод static async getInitialProps(), в котором предлагается проводить асинхронную загрузку данных. Решение с Apollo graphql client может быть использовано для компонента произвольного уровня вложенности.
Продолжим работу с проектом который рассматривался в предыдущем сообщении. Например, этот метод статический, следовательно не имеет доступ к экземпляру компонента, метод реализован только для компонента самого верхнего уровня и отсутствует у вложенных компонентов. За кадром ApolloProvider определяет какие запросы нужно выполнить для рендеринга компонентов с учетом выбранного роута, выполняет эти запросы и передает в компоненты при рендеринге. В серверном коде есть два ключевых момента: использование в качестве корневого элемента компонент ApolloProvider client= и асинхронное получение данных функцией await getDataFromTree(App).

...
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();
}

Соответственно, для восстановления данных на клиенте необходимо восстановить состояние клиента передав параметр в конструктор клиента: 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'));

Код этого примера я поместил в ветку ssr репозитария.

Если API grqphql реализованы на том же сервере, где реализован SSR, есть возможность избежать запросов API через сеть (как это практически всегда делают универсальные приложения) а запрашивать нужные функции grqphql их непосредственным вызовом внутри node.js. Таким образом, реализация серверного рендеринга и универсальных приложений при помощи Apollo graphql client очень лаконична и мало отличается от реализации чисто клиентского рендеринга.

apapacy@gmail.com
20 мая 2018 года.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть