与客户端渲染相比,我更喜欢对用户交互很少的应用程序使用服务器端渲染。而 webpack 是编译服务器端代码的选择。
有一个场景我想在组件渲染后更新表格的marginTop 。如果是客户端渲染,会列出如下实现
componentDidMount() {
const node = ReactDOM.findDOMNode(this.refs.table);
node.style.marginTop = `-${height}`;
}
但是,在 ssr 上,组件渲染时永远不会调用 componentDidMount。所以我把这些代码放在componentWillMount中,并更新源代码如下
document.addEventListener("DOMContentLoaded", function(event) {
const node = document.getElementById('table');
node.style.marginTop = `-${height}`;
});
然后它还有其他问题。
document is not defined on server
我知道原因,这是因为代码是在节点环境中运行的。没有像浏览器环境那样的文档种类。我能想到的一种方法是将代码放在renderPage 函数中,该函数用于将 React 组件呈现为服务器端Server Rendering上的 html 字符串。但是如果将事件处理程序放在顶级上下文中,它将污染其他呈现的页面。
router.get('*', ctx => {
match({ routes: routes, location: ctx.url }, (err, redirect, props) => {
if (err) {
ctx.throw(err.message, 500);
} else if (redirect) {
ctx.redirect(redirect.pathname + redirect.search)
} else if (props) {
const appHtml = renderToString(<RouterContext {...props}/>);
ctx.body = renderPage(appHtml);
} else {
ctx.throw(404, 'not fount');
}
})
})
function renderPage(appHtml) {
return `
<!doctype html public="storage">
<html>
<meta charset=utf-8/>
<title>My First React Router App</title>
<div id=app>${appHtml}</div>
<script type='text/javascript'>
document.addEventListener("DOMContentLoaded", function(event) {
const node = document.getElementById('table');
node.style.marginTop = `-${height}`;
});
</script>
`
}
我还找到了其他解决方案。用于在全局范围内绑定事件的 React 组件。. 我不认为它是最好的解决方案。
所以我想问有没有更好的方法来操作通常放在componentDidMount或componentDidUpdate中的 DOM 节点,如客户端渲染。