- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的组件目前在浏览器上水合,这是我想避免的事情。当您访问该链接时,我希望它预先包含所有需要显示的数据,即在服务器上呈现。目前,该组件如下所示:
import { graphql } from "react-apollo";
import gql from 'graphql-tag';
import withData from "../../apollo/with-data";
import getPostsQuery from '../../apollo/schemas/getPostsQuery.graphql';
const renderers = {
paragraph: (props) => <Typography variant="body2" gutterBottom {...props} />,
};
const GET_POSTS = gql`${getPostsQuery}`;
const PostList = ({data: {error, loading, posts}}) => {
let payload;
if(error) {
payload = (<div>There was an error!</div>);
} else if(loading) {
payload = (<div>Loading...</div>);
} else {
payload = (
<>
{posts.map((post) => (
<div>
<div>{post.title}</div>
<div>{post.body}</div>
</div>
))}
</>
);
}
return payload;
};
export default withData(graphql(GET_POSTS)(PostList));
如您所见,它显示文本 Loading...
一开始是因为它在后台获取帖子。我不想要那个。我希望它已经与获取的数据一起预水化。
作为引用,我的 Apollo 初始化如下所示:
// apollo/with-data.js
import React from "react";
import PropTypes from "prop-types";
import { ApolloProvider, getDataFromTree } from "react-apollo";
import initApollo from "./init-apollo";
export default ComposedComponent => {
return class WithData extends React.Component {
static displayName = `WithData(${ComposedComponent.displayName})`;
static propTypes = {
serverState: PropTypes.object.isRequired
};
static async getInitialProps(ctx) {
const headers = ctx.req ? ctx.req.headers : {};
let serverState = {};
// Evaluate the composed component's getInitialProps()
let composedInitialProps = {};
if (ComposedComponent.getInitialProps) {
composedInitialProps = await ComposedComponent.getInitialProps(ctx);
}
// Run all graphql queries in the component tree
// and extract the resulting data
if (!process.browser) {
const apollo = initApollo(headers);
// Provide the `url` prop data in case a graphql query uses it
const url = { query: ctx.query, pathname: ctx.pathname };
// Run all graphql queries
const app = (
<ApolloProvider client={apollo}>
<ComposedComponent url={url} {...composedInitialProps} />
</ApolloProvider>
);
await getDataFromTree(app);
// Extract query data from the Apollo's store
const state = apollo.getInitialState();
serverState = {
apollo: {
// Make sure to only include Apollo's data state
data: state.data
}
};
}
return {
serverState,
headers,
...composedInitialProps
};
}
constructor(props) {
super(props);
this.apollo = initApollo(this.props.headers, this.props.serverState);
}
render() {
return (
<ApolloProvider client={this.apollo}>
<ComposedComponent {...this.props} />
</ApolloProvider>
);
}
};
};
// apollo/init-apollo.js
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloClient } from 'apollo-client';
import { ApolloLink } from 'apollo-link';
import { onError } from 'apollo-link-error';
import { HttpLink } from 'apollo-link-http';
import fetch from 'isomorphic-fetch';
let apolloClient = null;
// Polyfill fetch() on the server (used by apollo-client)
if (!process.browser) {
global.fetch = fetch;
}
const create = (headers, initialState) => new ApolloClient({
initialState,
link: ApolloLink.from([
onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message, locations, path }) => console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
));
}
if (networkError) console.log(`[Network error]: ${networkError}`);
}),
new HttpLink({
// uri: 'https://dev.schandillia.com/graphql',
uri: process.env.CMS,
credentials: 'same-origin',
}),
]),
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
cache: new InMemoryCache(),
});
export default function initApollo(headers, initialState = {}) {
// Make sure to create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (!process.browser) {
return create(headers, initialState);
}
// Reuse client on the client-side
if (!apolloClient) {
apolloClient = create(headers, initialState);
}
return apolloClient;
}
更新:我尝试在 https://github.com/zeit/next.js/tree/canary/examples/with-apollo 合并官方 withApollo 示例进入我的项目,但它在 getDataFromTree()
上抛出一个不变错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
对于 /init/apollo.js
,我使用了与示例存储库中完全相同的代码, /components/blog/PostList.jsx
, 和 /pages/Blog/jsx
文件。我的具体情况的唯一区别是我有一个明确的 _app.jsx
内容如下:
/* eslint-disable max-len */
import '../static/styles/fonts.scss';
import '../static/styles/style.scss';
import '../static/styles/some.css';
import CssBaseline from '@material-ui/core/CssBaseline';
import { ThemeProvider } from '@material-ui/styles';
import jwt from 'jsonwebtoken';
import withRedux from 'next-redux-wrapper';
import App, {
Container,
} from 'next/app';
import Head from 'next/head';
import React from 'react';
import { Provider } from 'react-redux';
import makeStore from '../reducers';
import mainTheme from '../themes/main-theme';
import getSessIDFromCookies from '../utils/get-sessid-from-cookies';
import getLanguageFromCookies from '../utils/get-language-from-cookies';
import getUserTokenFromCookies from '../utils/get-user-token-from-cookies';
import removeFbHash from '../utils/remove-fb-hash';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let userToken;
let sessID;
let language;
if (ctx.isServer) {
ctx.store.dispatch({ type: 'UPDATEIP', payload: ctx.req.headers['x-real-ip'] });
userToken = getUserTokenFromCookies(ctx.req);
sessID = getSessIDFromCookies(ctx.req);
language = getLanguageFromCookies(ctx.req);
const dictionary = require(`../dictionaries/${language}`);
ctx.store.dispatch({ type: 'SETLANGUAGE', payload: dictionary });
if(ctx.res) {
if(ctx.res.locals) {
if(!ctx.res.locals.authenticated) {
userToken = null;
sessID = null;
}
}
}
if (userToken && sessID) { // TBD: validate integrity of sessID
const userInfo = jwt.verify(userToken, process.env.JWT_SECRET);
ctx.store.dispatch({ type: 'ADDUSERINFO', payload: userInfo });
}
ctx.store.dispatch({ type: 'ADDSESSION', payload: sessID }); // component will be able to read from store's state when rendered
}
const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};
return { pageProps };
}
componentDidMount() {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentNode.removeChild(jssStyles);
}
// Register serviceWorker
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/serviceWorker.js'); }
// Handle FB's ugly redirect URL hash
removeFbHash(window, document);
}
render() {
const { Component, pageProps, store } = this.props;
return (
<Container>
<Head>
<meta name="viewport" content="user-scalable=0, initial-scale=1, minimum-scale=1, width=device-width, height=device-height, shrink-to-fit=no" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="194x194" href="/favicon-194x194.png" />
<link rel="icon" type="image/png" sizes="192x192" href="/android-chrome-192x192.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#663300" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="msapplication-TileImage" content="/mstile-144x144.png" />
</Head>
<ThemeProvider theme={mainTheme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</ThemeProvider>
</Container>
);
}
}
export default withRedux(makeStore)(MyApp);
摆脱这个文件不是一个选项,因为这是我处理一些预加载 cookie 逻辑的地方。
作为引用,repo 位于 https://github.com/amitschandillia/proost/tree/master/web
最佳答案
使用 Next.js 和 Apollo 时,您希望实现 2 个关键目标:SSR 和缓存网络数据。两者很难取得平衡。但这是可能的。
实现方式是:
现在,如果您有一些页面数据需要编辑、添加或删除,并且您希望页面在更改后更新而不刷新页面,以上是不够的。因为例如,如果您编辑数据,典型/推荐的 Apollo 方法是不做任何事情。 Apollo 会神奇地为您处理这一切。除了初始数据必须来自 apollo 缓存并且它必须有一个 Id 字段。现在您已经直接从服务器加载了初始数据,很可能您没有从以前缓存的数据中读取数据。
因此需要下面的第 2 步来启用数据更改时的数据自动刷新。
通过这种方式,您可以继续使用所有您最喜欢的和最新的工具,例如 useQuery 和 getDataFromTree,而无需费力。
关于javascript - 将 Apollo Client 与 NextJS 一起使用时服务器端渲染数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58021561/
SQLite、Content provider 和 Shared Preference 之间的所有已知区别。 但我想知道什么时候需要根据情况使用 SQLite 或 Content Provider 或
警告:我正在使用一个我无法完全控制的后端,所以我正在努力解决 Backbone 中的一些注意事项,这些注意事项可能在其他地方更好地解决......不幸的是,我别无选择,只能在这里处理它们! 所以,我的
我一整天都在挣扎。我的预输入搜索表达式与远程 json 数据完美配合。但是当我尝试使用相同的 json 数据作为预取数据时,建议为空。点击第一个标志后,我收到预定义消息“无法找到任何内容...”,结果
我正在制作一个模拟 NHL 选秀彩票的程序,其中屏幕右侧应该有一个 JTextField,并且在左侧绘制弹跳的选秀球。我创建了一个名为 Ball 的类,它实现了 Runnable,并在我的主 Draf
这个问题已经有答案了: How can I calculate a time span in Java and format the output? (18 个回答) 已关闭 9 年前。 这是我的代码
我有一个 ASP.NET Web API 应用程序在我的本地 IIS 实例上运行。 Web 应用程序配置有 CORS。我调用的 Web API 方法类似于: [POST("/API/{foo}/{ba
我将用户输入的时间和日期作为: DatePicker dp = (DatePicker) findViewById(R.id.datePicker); TimePicker tp = (TimePic
放宽“邻居”的标准是否足够,或者是否有其他标准行动可以采取? 最佳答案 如果所有相邻解决方案都是 Tabu,则听起来您的 Tabu 列表的大小太长或您的释放策略太严格。一个好的 Tabu 列表长度是
我正在阅读来自 cppreference 的代码示例: #include #include #include #include template void print_queue(T& q)
我快疯了,我试图理解工具提示的行为,但没有成功。 1. 第一个问题是当我尝试通过插件(按钮 1)在点击事件中使用它时 -> 如果您转到 Fiddle,您会在“内容”内看到该函数' 每次点击都会调用该属
我在功能组件中有以下代码: const [ folder, setFolder ] = useState([]); const folderData = useContext(FolderContex
我在使用预签名网址和 AFNetworking 3.0 从 S3 获取图像时遇到问题。我可以使用 NSMutableURLRequest 和 NSURLSession 获取图像,但是当我使用 AFHT
我正在使用 Oracle ojdbc 12 和 Java 8 处理 Oracle UCP 管理器的问题。当 UCP 池启动失败时,我希望关闭它创建的连接。 当池初始化期间遇到 ORA-02391:超过
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve
引用这个plunker: https://plnkr.co/edit/GWsbdDWVvBYNMqyxzlLY?p=preview 我在 styles.css 文件和 src/app.ts 文件中指定
为什么我的条形这么细?我尝试将宽度设置为 1,它们变得非常厚。我不知道还能尝试什么。默认厚度为 0.8,这是应该的样子吗? import matplotlib.pyplot as plt import
当我编写时,查询按预期执行: SELECT id, day2.count - day1.count AS diff FROM day1 NATURAL JOIN day2; 但我真正想要的是右连接。当
我有以下时间数据: 0 08/01/16 13:07:46,335437 1 18/02/16 08:40:40,565575 2 14/01/16 22:2
一些背景知识 -我的 NodeJS 服务器在端口 3001 上运行,我的 React 应用程序在端口 3000 上运行。我在 React 应用程序 package.json 中设置了一个代理来代理对端
我面临着一个愚蠢的问题。我试图在我的 Angular 应用程序中延迟加载我的图像,我已经尝试过这个2: 但是他们都设置了 src attr 而不是 data-src,我在这里遗漏了什么吗?保留 d
我是一名优秀的程序员,十分优秀!