同构React应用客户端重渲染时如何获取服务端传递的Props?
解决同构React应用中服务端Props传递到客户端的问题
这个问题我太熟悉了——你遇到的是JavaScript对象直接插入模板字符串时的序列化问题。当你在<script>里直接写${passedProps},JavaScript会把对象转换成默认的字符串表示[object Object],这在客户端解析时会触发语法错误,自然就没法执行渲染了。
下面给你两种可靠的解决方法,都是同构React应用里传递初始props的标准做法:
方法一:使用全局变量传递序列化后的Props
这是最常用的方案,核心思路是把服务端的props序列化为JSON字符串,插入到客户端的全局变量中,这样客户端就能直接读取到和服务端完全一致的初始数据。
修改你的renderFullPage函数:
function renderFullPage(html, passedProps) { // 把props序列化为合法的JSON字符串,自动处理转义 const serializedProps = JSON.stringify(passedProps); return ` <!DOCTYPE html> <html lang="en"> <head> ........ </head> <body> <div id="root">${html}</div> ...... <script> // 定义全局变量存储初始props,用双下划线命名避免冲突 window.__INITIAL_PROPS__ = ${serializedProps}; function render() { ReactDOM.render( React.createElement(myComponent, window.__INITIAL_PROPS__), document.querySelector('#root') ); } render(); </script> </body> </html>`; }
为什么这能行?
JSON.stringify(passedProps)会把你的{'foo':'bar'}转换成字符串{"foo":"bar"},这是完全合法的JavaScript对象字面量,插入到<script>里不会有语法问题。- 全局变量
window.__INITIAL_PROPS__可以被客户端的render函数直接读取,保证了服务端和客户端的初始props完全一致,避免了 hydration 不匹配的问题。
方法二:通过DOM的data属性传递Props
如果你不想用全局变量,也可以把序列化后的props存在DOM元素的data-*属性里,客户端再读取解析:
修改renderFullPage里的根节点:
<div id="root" data-initial-props="${serializedProps}">${html}</div>
然后客户端的render函数改成:
function render() { const rootElement = document.querySelector('#root'); // 解析data属性里的JSON字符串 const initialProps = JSON.parse(rootElement.dataset.initialProps); ReactDOM.render( React.createElement(myComponent, initialProps), rootElement ); } render();
这种方式更符合HTML语义化,但全局变量的方式在同构应用里更普遍,因为读取起来更直接。
最后提醒一下:不管用哪种方式,都要确保passedProps是可以被JSON序列化的(比如不能包含函数、Symbol等JSON不支持的类型),否则JSON.stringify会忽略这些属性,导致数据不一致。
内容的提问来源于stack exchange,提问作者Yang Yubo
相关产品推荐
相关产品推荐

