【发布时间】:2019-03-28 06:54:18
【问题描述】:
我遇到了gatsby develop 和gatsby build 生成的站点之间行为不一致的问题。结果是一个可以在开发中工作但不能在生产中工作的网站。
我的网站摘要:
一个简单的类似博客的网站(个人资料而不是博客文章)。指数 page 是一个人员列表,该列表中的每个项目都链接到该人员的个人资料页面。
我正在使用Gatsby 来构建网站。我的数据(个人资料)是托管在 Contentful headless CMS 上的条目。我正在使用gatsby-source-contentful 源插件。
问题的高级描述
我无法在索引页面上打乱个人资料列表项的顺序。我的网站超出任何基本 gatsby 教程的唯一行为是我想随机化我的索引页面上的个人资料列表(让每个人都有公平的机会被列在顶部)。
gatsby build 生成一个静态索引页面,其中的列表以一种排列方式排列。
当在浏览器中加载时,ThumbList 组件将这些项目重新洗牌到渲染上的另一个排列,并且一些子元素没有被 react 正确管理并在其他元素移动时卡住。例如,这会导致配置文件图像与错误的名称配对。
代码
为了便于阅读,对以下代码进行了一些总结。
src/pages/index.js:
import React from "react"
import Layout from "../components/layout"
import ThumbList from "../components/thumbList"
import { graphql } from "gatsby"
export default ({data}) => {
// people are called "creators" in the app
const creatorData = data.allContentfulCreator.edges
const shuffledData = shuffle(creatorData.slice(0))
return (
<Layout>
<ThumbList data={shuffledData} />
</Layout>
)
}
const shuffle = (a) => {
// Fisher-Yates randomized array in-place shuffle algo
// ...
return a
}
export const query = graphql`
{
allContentfulCreator {
edges {
node {
id
slug
name
bio {
id
bio
}
mainImage {
file {
url
}
}
}
}
}
}
`
src/components/thumbList.js:
import React from "react"
import { Link } from "gatsby"
// A list of creator profile links, with name and picture thumbnail
export default ({data}) => {
return (
<div>
<ul>
{
data.map(({node}) => {
const creator = node
const link = "/" + creator.slug
const image = "https:" + creator.mainImage.file.url
return (
<li key={creator.id}>
<Link to={link}>
{creator.name}
</Link>
<img src={image} />
</li>
)
})
}
</ul>
</div>
)
}
gatsby build 的结果是一个 index.html,其中包含:
<ul>
<li>
<a href="/alice">
Alice
</a>
<img src="cdn.com/alice.jpg">
</li>
<li>
<a href="/bob">
Bob
</a>
<img src="cdn.com/bob.jpg">
</li>
<li>
<a href="/eve">
Eve
</a>
<img src="cdn.com/eve.jpg">
</li>
</ul>
但是,当在浏览器中查看索引页面时(通过gatsby serve 或站点的部署版本),live react ThumbList 组件再次在其渲染方法中打乱数据。
结果重新渲染的html:
<ul>
<li>
<a href="/alice">
Bob
</a>
<img src="cdn.com/alice.jpg">
</li>
<li>
<a href="/bob">
Eve
</a>
<img src="cdn.com/bob.jpg">
</li>
<li>
<a href="/eve">
Alice
</a>
<img src="cdn.com/eve.jpg">
</li>
</ul>
这里只有文本节点被重新排列以匹配新的顺序(通过控制台记录数组顺序确认),但链接和图像元素仍然停留在它们在静态构建中的位置。现在名称、图像和链接都被打乱了。
另外两点需要注意:
-
gatsby develop一切正常。我猜这是因为在开发中 index.html 是在正文中没有静态内容的情况下生成的 - 允许从一开始就完全控制 DOM 而没有 静态脚手架来迷惑它。 - 使用反应检查器,我看到虚拟 DOM 和真实 DOM 不同步。 React 认为它已经正确地打乱了列表项。 Inspector 显示如下内容:
(为了便于阅读,非常缩写)
<ul>
<li key="165e2405">
<GatsbyLink to="/bob">
Bob
</GatsbyLink>
<img src="cdn.com/bob.jpg"></img>
</li>
<li key="067f9afc">
<GatsbyLink to="/eve">
Eve
</GatsbyLink>
<img src="cdn.com/eve.jpg"></img>
</li>
<li key="ca4b82bf">
<GatsbyLink to="/alice">
Alice
</GatsbyLink>
<img src="cdn.com/alice.jpg"></img>
</li>
</ul>
我的问题
- 这只是一种不像盖茨比的方法吗? This description of a "Hybrid app page" 似乎暗示您可以拥有静态或动态组件。我想我正在尝试两种方式:我想要
在构建过程中通过 graphql 从内容中获取配置文件,因此可以通过静态 HTML + 预构建的 json 数据文件(例如
/static/d/556/path---index-6a9-L7r5Sntxcv3RUIoHYIR3Qqm9Jmg.json)获得,但是 然后我想动态地打乱该数据并在渲染时重新排列 DOM。盖茨比不可能吗?我是否需要在构建期间放弃预取的数据,只考虑动态组件并获取 通过componentDidMount中的 Contentful API 获取数据? - 如果这种方法应该没问题,我做错了什么?
- 如果这种方法不是惯用的,有没有办法在构建时修改(洗牌)通过 graphql 查询的数据?如果数据只在构建时洗牌,而不在浏览器的运行时重新洗牌,我实际上会更开心——我可以自动化网站每隔一小时左右重建一次,并且网站对客户来说可能更加静态.
【问题讨论】:
-
一些事情 - 如果你使用
setTimeout对节点进行随机化并在 React 生命周期方法componentWillMount中调用该函数会怎样?只是一个想法,但是该组合可以在用户加载它们之前创建节点的定时洗牌,而不管它们如何存储在数据库中。是的,它是客户端的,但动作如此之小,以至于我无法想象会有多大的成功。另一种选择是执行 lambda 函数,在页面加载后执行随机播放服务器端,这将是混合应用程序选项。看起来有点矫枉过正,但你也可以这样做。
标签: javascript reactjs gatsby