在此处查看此操作:https://www.slowdownshow.org/
大多数情况下,我尝试了文档中建议的内容: https://www.apollographql.com/docs/react/features/server-side-rendering
这还不清楚。我是否假设如果实现存储补水功能,则不需要发生Apollo客户端xhr请求以获取数据?如果是这样的话,那么问题是我尝试了文档建议的商店补水建议,但是文档有点模棱两可
<script>
window.__APOLLO_STATE__ = JSON.stringify(client.extract());
</script>
在这种情况下,客户是什么?我相信这是ApolloClient。但这不是方法,而是对象,如果在这里使用它,我会收到类似
的错误消息 Warning: Failed context type: Invalid context
客户端of type
功能supplied to
组件, expected
对象.
如果Store Rehydration技术不是防止不必要的客户端重新渲染的方法-我不清楚这是什么。
这是相关的服务器代码:
import React from 'react';
import ReactDOM from 'react-dom/server';
import { ApolloProvider, renderToStringWithData } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import FragmentMatcher from '../shared/graphql/FragmentMatcher';
import { HelmetProvider } from 'react-helmet-async';
import { ServerLocation } from 'apm-titan';
import App from '../shared/App';
import fs from 'fs';
import os from 'os';
import {
globalHostFunc,
replaceTemplateStrings,
isFresh,
apm_etag,
siteConfigFunc
} from './utils';
export default function ReactAppSsr(app) {
app.use((req, res) => {
const helmetContext = {};
const filepath =
process.env.APP_PATH === 'relative' ? 'build' : 'current/build';
const forwarded = globalHostFunc(req).split(':')[0];
const siteConfig = siteConfigFunc(forwarded);
const hostname = os.hostname();
const context = {};
const cache = new InMemoryCache({ fragmentMatcher: FragmentMatcher });
let graphqlEnv = hostname.match(/dev/) ? '-dev' : '';
graphqlEnv = process.env.NODE_ENV === 'development' ? '-dev' : graphqlEnv;
const graphqlClient = (graphqlEnv) => {
return new ApolloClient({
ssrMode: false,
cache,
link: createHttpLink({
uri: `https://xxx${graphqlEnv}.xxx.org/api/v1/graphql`,
fetch: fetch
})
});
};
let template = fs.readFileSync(`${filepath}/index.html`).toString();
const component = (
<ApolloProvider client={graphqlClient}>
<HelmetProvider context={helmetContext}>
<ServerLocation url={req.url} context={context}>
<App forward={forwarded} />
</ServerLocation>
</HelmetProvider>
</ApolloProvider>
);
renderToStringWithData(component).then(() => {
const { helmet } = helmetContext;
let str = ReactDOM.renderToString(component);
const is404 = str.match(/Not Found\. 404/);
if (is404?.length > 0) {
str = 'Not Found 404.';
template = replaceTemplateStrings(template, '', '', '', '');
res.status(404);
res.send(template);
return;
}
template = replaceTemplateStrings(
template,
helmet.title.toString(),
helmet.meta.toString(),
helmet.link.toString(),
str
);
template = template.replace(/__GTMID__/g, `${siteConfig.gtm}`);
const apollo_state = ` <script>
window.__APOLLO_STATE__ = JSON.stringify(${graphqlClient.extract()});
</script>
</body>`;
template = template.replace(/<\/body>/, apollo_state);
res.set('Cache-Control', 'public, max-age=120');
res.set('ETag', apm_etag(str));
if (isFresh(req, res)) {
res.status(304);
res.send();
return;
}
res.send(template);
res.status(200);
});
});
}
客户端:
import App from '../shared/App';
import React from 'react';
import { hydrate } from 'react-dom';
import { ApolloProvider } from 'react-apollo';
import { HelmetProvider } from 'react-helmet-async';
import { client } from '../shared/graphql/graphqlClient';
import '@babel/polyfill';
const graphqlEnv = window.location.href.match(/local|dev/) ? '-dev' : '';
const graphqlClient = client(graphqlEnv);
const Wrapped = () => {
const helmetContext = {};
return (
<HelmetProvider context={helmetContext}>
<ApolloProvider client={graphqlClient}>
<App />
</ApolloProvider>
</HelmetProvider>
);
};
hydrate(<Wrapped />, document.getElementById('root'));
if (module.hot) {
module.hot.accept();
}
graphqlCLinet.js:
import fetch from 'cross-fetch';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import FragmentMatcher from './FragmentMatcher';
const cache = new InMemoryCache({ fragmentMatcher: FragmentMatcher });
export const client = (graphqlEnv) => {
return new ApolloClient({
ssrMode: true,
cache,
link: createHttpLink({
uri: `https://xxx${graphqlEnv}.xxx.org/api/v1/graphql`,
fetch: fetch
})
});
};
FragmentMatcher.js:
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
const FragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData: {
__schema: {
types: [
{
kind: 'INTERFACE',
name: 'resourceType',
possibleTypes: [
{ name: 'Episode' },
{ name: 'Link' },
{ name: 'Page' },
{ name: 'Profile' },
{ name: 'Story' }
]
}
]
}
}
});
export default FragmentMatcher;
查看客户端在行动中的重新渲染
https://www.slowdownshow.org/
在上面代码的生产版本中,
我没有进行状态补液window.__APOLLO_STATE__ = JSON.stringify(${graphqlClient.extract()});
,因为我没有进行补液
答案 0 :(得分:1)
所以一旦我意识到自己犯了一个错误,答案就很简单。我需要放
window.__APOLLO_STATE__ = JSON.stringify(client.extract());
</script>
在所有其他内容之前,可以对其进行阅读和使用。
此const apollo_state = ` <script>
window.__APOLLO_STATE__ = JSON.stringify(${graphqlClient.extract()});
</script>
</body>`;
template = template.replace(/<\/body>/, apollo_state);
需要<head>
向上而不是身体向下移动。真是个傻瓜,但让我绊了一会儿