reactjs - 我可以强制水合物向元素添加属性吗?
问题描述
我有以下组件在服务器(SSR)和浏览器中呈现时处理不同的事情。
它不会为元素分配 ID 以“修复”古怪的浏览器页内锚导航(由 JS 处理)。
问题是当应用程序被水合时没有添加 ID。有没有办法强制水合物添加ID?
class Heading extends Component<HeadingProps, HeadingState> {
constructor(props: HeadingProps) {
super(props)
this.state = {
hover: false,
}
}
render() {
let _slug = slug(reactNodeToString(this.props.children))
if (typeof window !== "undefined") {
return React.createElement(
`h${this.props.level}`,
{
id: _slug,
style: {
position: "relative",
},
onMouseEnter: () => {
this.setState({
hover: true,
})
},
onMouseLeave: () => {
this.setState({
hover: false,
})
},
},
<Fragment>
<HeadingAnchor show={this.state.hover}>
<Anchor
story={this.props.story}
hashLinkOffset={this.props.hashLinkOffset}
href={`#${_slug}`}
title={`#${_slug}`}
className="heading-anchor"
>
{[
<Fragment key={`#${_slug}`}>
<Icon icon={["fas", "link"]} size="xs" />
</Fragment>,
]}
</Anchor>
</HeadingAnchor>
{this.props.children}
</Fragment>
)
} else {
// SSR-mode
return React.createElement(
`h${this.props.level}`,
this.props.children
)
}
}
}
解决方案
嗯……是的,不是的。对于第一次渲染,不,你不能。原因在 React docs about hydration 中有解释:
React 期望服务器和客户端之间呈现的内容是相同的。它可以修补文本内容的差异,但您应该将不匹配视为错误并修复它们。在开发模式下,React 会警告水合期间的不匹配。无法保证在不匹配的情况下会修补属性差异。出于性能原因,这很重要,因为在大多数应用程序中,不匹配的情况很少见,因此验证所有标记的成本非常高。
https://reactjs.org/docs/react-dom.html#hydra
所以基本上,React hydration 期望在客户端中被 hydration 的内容是完全相同的。它会尝试修补一些东西,但在这件事上,属性大多被忽略了。
那你怎么解决?状态。
你不应该在你的函数中使用typeof window
检查。render
相反,请使用一些状态变量,例如isHydrated
在componentDidMount
阶段中设置。
像这样,在你的类的精简版本中:
type HeadingProps = {
level: number;
children: React.ReactNode;
}
type HeadingState = {
isHydrated: boolean;
}
class Heading extends Component<HeadingProps, HeadingState> {
constructor(props: HeadingProps) {
super(props)
this.state = {
isHydrated: false
}
}
componentDidMount() {
this.setState({
isHydrated: true
})
}
render() {
if (this.state.isHydrated) {
return React.createElement(
`h${this.props.level}`,
{
id: "hydrated",
},
this.props.children
)
} else {
// SSR-mode
return React.createElement(
`h${this.props.level}`,
this.props.children
)
}
}
}
钩子版本将是setState
在useEffect
.
componentDidMount
并且useEffect
仅称为客户端。
推荐阅读
- tsql - 为什么我通过 Openquery 通过 Hortonworks ODBC 驱动程序在 SSMS 中运行的 Hive QL 查询会产生错误?
- java - 给定的反向名称
- google-sheets - 谷歌表查询 - 排除最后一行
- python - 熊猫在另一列中出现某个值之前选择行的子集
- javascript - 是否可以在花式框中动态创建更大的图像?
- ibm-cloud - 如何在 IBM Bluemix 网站上更新 node-red
- c# - ASP.NET 导航按钮
- amazon-web-services - 自动与客户端共享来自 EC2 实例的单个文件夹
- json - 发送看起来要反序列化的格式化纯文本的 Json
- swift - stopAnimating 移除当前图像