通过解析 html 字符串并将结果节点转换为 React 元素,可以将清理过的 HTML 变成可以在服务器和客户端上运行的 React 组件。
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const str = `<div>divContent<p> para 1</p><p> para 2</p><gallery image-ids="" /><player video-id="" /><p> para 3</p><gallery image-ids="[1, 3]"/></div>`;
var parse = require('xml-parser');
const Gallery = () => React.createElement('div', null, 'Gallery comp');
const Player = () => React.createElement('div', null, 'Player comp');
const componentMap = {
gallery: Gallery,
player: Player
};
const traverse = (cur, props) => {
return React.createElement(
componentMap[cur.name] || cur.name,
props,
cur.children.length === 0 ? cur.content: Array.prototype.map.call(cur.children, (c, i) => traverse(c, { key: i }))
);
};
const domTree = parse(str).root;
const App = traverse(
domTree
);
console.log(
ReactDOMServer.renderToString(
App
)
);
但是请注意,正如您所提到的,您真正需要的并不是 JSX/TSX,而是用于 React 渲染器的 React 节点树(在本例中为 ReactDOM)。JSX 只是语法糖,除非您想在代码库中维护 React 输出,否则不需要来回转换它。
请原谅过度简化的 html 解析。它仅用于说明目的。您可能希望使用更符合规范的库来解析输入 html 或适合您的用例的内容。
确保客户端 bundle 获得完全相同的App
组件,否则你可能 React 的客户端脚本会重新创建 DOM 树,你将失去服务器端渲染的所有好处。
您也可以通过上述方法利用 React 16 的流式传输。
解决props问题
props将作为属性从树中提供给您,并且可以作为props传递(当然要仔细考虑您的用例)。
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const str = `<div>divContent<p> para 1</p><p> para 2</p><gallery image-ids="" /><player video-id="" /><p> para 3</p><gallery image-ids="[1, 3]"/></div>`;
var parse = require('xml-parser');
const Gallery = props => React.createElement('div', null, `Gallery comp: Props ${JSON.stringify(props)}`);
const Player = () => React.createElement('div', null, 'Player comp');
const componentMap = {
gallery: Gallery,
player: Player
};
const attrsToProps = attributes => {
return Object.keys(attributes).reduce((acc, k) => {
let val;
try {
val = JSON.parse(attributes[k])
} catch(e) {
val = null;
}
return Object.assign(
{},
acc,
{ [ k.replace(/\-/g, '') ]: val }
);
}, {});
};
const traverse = (cur, props) => {
const propsFromAttrs = attrsToProps(cur.attributes);
const childrenNodes = Array.prototype.map.call(cur.children, (c, i) => {
return traverse(
c,
Object.assign(
{},
{
key: i
}
)
);
});
return React.createElement(
componentMap[cur.name] || cur.name,
Object.assign(
{},
props,
propsFromAttrs
),
cur.children.length === 0 ? cur.content: childrenNodes
);
};
const domTree = parse(str).root;
const App = traverse(
domTree
);
console.log(
ReactDOMServer.renderToString(
App
)
);
不过要小心自定义属性 - 您可能想要遵循这个 rfc。如果可能的话,坚持使用驼峰式命名法。