- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个项目使用 react 路由器 v3 仅出于一个原因。原因是需要使用数据预取进行服务器端渲染,最方便的方法是保留 集中路由配置在 object
或 array
并遍历匹配的元素以从服务器端的 API 获取数据。稍后的数据将与响应 HTML 一起传递给客户端,并存储在 JSON 格式字符串的变量中。
应用程序也使用代码拆分,但是使用 babel-plugin-transform-ensure-ignore
在服务器端我可以直接获取组件而不是延迟加载和本地人 import
方法将仅在客户端使用。
然而,上述结构不适用于 react 路由器 v5 ,因为它有点困难,因为我不能使用 @loadable/components
,如 react 路由器官方文件建议。根据我的观察 @loadable/components
只是在服务器端生成 HTML,而不是给我实现 fetch
的组件负责服务器端逻辑的方法。
所以想请教一下的结构好webpack + react-router v5 + ssr + 数据预取 + redux + 代码拆分
我认为这很复杂,没有通用的解决方案,但是我可能错了。
任何方向或建议表示赞赏。
最佳答案
我从未尝试过@loadable/components
,但我用自定义的代码拆分实现做了类似的事情(SSR + 代码拆分 + 数据预取),我相信你应该改变你的数据预取方法。
如果我说得对,你的问题是你试图干预正常的 React 渲染过程,提前推断出你的渲染中将使用哪些组件,从而应该预取哪些数据。这种干预/推论不是 React API 的一部分,虽然我看到不同的人使用一些未记录的内部 React 东西来实现它,但从长远来看,它们都很脆弱,并且容易出现像你这样的问题。
我相信,一个更好的防弹方法是将 SSR 执行为几个正常的渲染 channel ,在每个 channel 中收集要预取的数据列表,获取它们,然后从一开始就使用更新重复渲染状态。我正在努力想出一个清晰的解释,但让我试试这样的例子。
比如说,一个组件 <A>
您的应用程序树中的某处取决于异步获取的数据,这些数据应该存储在 some.path
你的 Redux 商店。考虑一下:
context
,或者使用 React 的 Context API 创建一个单独的)。 ReactDOMServer.renderToString(..)
对整个应用程序执行非常基本的 SSR . <A>
在你的应用程序树的某个地方,无论它是否被代码分割,如果一切设置正确,该组件将可以访问 Redux 存储和 SSR 上下文。所以,如果 <A>
看到当前渲染发生在服务器上,并且没有数据预取到 some.path
Redux 商店的,<A>
将“加载这些数据的请求”保存到 SSR 上下文中,并呈现一些占位符(或在没有预取这些数据的情况下呈现任何有意义的内容)。我所说的“加载这些数据的请求”是指 <A>
实际上可以触发一个异步函数,该函数将获取数据,并将相应的数据 promise 推送到上下文中的专用数组。 ReactDOMServer.renderToString(..)
完成您将拥有:呈现的 HTML 标记的当前版本,以及收集在 SSR 上下文对象中的一组数据获取 promise 。您可以在此处执行以下操作之一:const ssrContext = {
// That's the initial content of "Global State". I use a custom library
// to manage it with Context API; but similar stuff can be done with Redux.
state: {},
};
let markup;
const ssrStart = Date.now();
for (let round = 0; round < options.maxSsrRounds; ++round) {
// These resets are not in my original code, as they are done in my global
// state management library.
ssrContext.dirty = false;
ssrContext.pending = [];
markup = ReactDOM.renderToString((
// With Redux, you'll have Redux store provider here.
<GlobalStateProvider
initialState={ssrContext.state}
ssrContext={ssrContext}
>
<StaticRouter
context={ssrContext}
location={req.url}
>
<App />
</StaticRouter>
</GlobalStateProvider>
));
if (!ssrContext.dirty) break;
const timeout = options.ssrTimeout + ssrStart - Date.now();
const ok = timeout > 0 && await Promise.race([
Promise.allSettled(ssrContext.pending),
time.timer(timeout).then(() => false),
]);
if (!ok) break;
// Here you should take data resolved by "ssrContext.pending" promises,
// and place it into the correct paths of "ssrContext.state", before going
// to the next SSR iteration. In my case, my global state management library
// takes care of it, so I don't have to do it explicitly here.
}
// Here "ssrContext.state" should contain the Redux store content to send to
// the client side, and "markup" is the corresponding rendered HTML.
依赖异步数据的组件内部的逻辑将有点像这样:
function Component() {
// Try to get necessary async from Redux store.
const data = useSelector(..);
// react-router does not provide a hook for accessing the context,
// and in my case I am getting it via my <GlobalStateProvider>, but
// one way or another it should not be a problem to get it.
const ssrContext = useSsrContext();
// No necessary data in Redux store.
if (!data) {
// We are at server.
if (ssrContext) {
ssrContext.dirty = true;
ssrContext.pending.push(
// A promise which resolves to the data we need here.
);
// We are at client-side.
} else {
// Dispatch an action to load data into Redux store,
// as appropriate for your setup.
}
}
return data ? (
// Return the complete component render, which requires "data"
// for rendering.
) : (
// Return an appropriate placeholder (e.g. a "loading" indicator).
);
}
关于javascript - React Router v5 附带代码拆分和使用服务器端渲染的数据预取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67352004/
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!