最近发布的React 16支持Portals(https://facebook.github.io/react/docs/portals.html), 也就是支持将子组件render到其它任何地方。Vuejs也支持类似的功能,见https://github.com/LinusBorg/portal-vue。
昨天尝试了下Portals功能,demo如下
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import jsdom from 'jsdom';
const { JSDOM } = jsdom;
const dom = new JSDOM(`
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<div id="domNode"></div>
</body>
</html>
`);
const document = dom.window.document;
const htmlNode = document.querySelector("html");
const appNode = document.querySelector("#app");
const domNode = document.querySelector("#domNode");
class Portals extends Component {
render() {
return ReactDOM.createPortal(
this.props.children,
domNode,
);
}
}
ReactDOM.render(
<Portals>
<h1>hello</h1>
<span>Hello React 16.</span>
</Portals>,
appNode
);
console.log('htmlNode -> ', htmlNode.outerHTML);
输出结果如下:
htmlNode -> <html><head></head><body>
<div id="app"></div>
<div id="domNode"><h1>hello</h1><span>Hello React 16.</span></div>
</body></html>
可以看到使用了Portals后,
下面来看下在使用服务端渲染时的代码:
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import ReactDOMServer from 'react-dom/server';
import jsdom from 'jsdom';
const { JSDOM } = jsdom;
const dom = new JSDOM(`
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<div id="domNode"></div>
</body>
</html>
`);
const document = dom.window.document;
const htmlNode = document.querySelector("html");
const domNode = document.querySelector("#domNode");
class Portals extends Component {
render() {
return ReactDOM.createPortal(
this.props.children,
domNode,
);
}
}
const str = ReactDOMServer.renderToString(
<Portals>
<h1>hello</h1>
<span>Hello React 16.</span>
</Portals>
);
console.log('str', str);
console.log('htmlNode -> ', htmlNode.outerHTML);
代码主体功能没差别,主要是ReactDOM.render改成了ReactDOMServer.renderToString,
但这次render没有成功,具体错误信息如下:
D:\work_react\react16-demo\node_modules\.npminstall\fbjs\0.8.16\fbjs\lib\invariant.js:49
throw error;
^
Invariant Violation: Objects are not valid as a React child (found: object with keys {$$typeof, key, children, containerInfo, implementation}). If you
meant to render a collection of children, use an array instead.
in Portals
at invariant (D:\work_react\react16-demo\node_modules\.npminstall\fbjs\0.8.16\fbjs\lib\invariant.js:42:15)
at traverseAllChildrenImpl (D:\work_react\react16-demo\node_modules\.npminstall\react\16.0.0\react\cjs\react.development.js:830:7)
at traverseAllChildren (D:\work_react\react16-demo\node_modules\.npminstall\react\16.0.0\react\cjs\react.development.js:858:10)
at mapIntoWithKeyPrefixInternal (D:\work_react\react16-demo\node_modules\.npminstall\react\16.0.0\react\cjs\react.development.js:934:3)
at toArray (D:\work_react\react16-demo\node_modules\.npminstall\react\16.0.0\react\cjs\react.development.js:981:3)
at ReactDOMServerRenderer.render (D:\work_react\react16-demo\node_modules\.npminstall\react-dom\16.0.0\react-dom\cjs\react-dom-server.node.developme
nt.js:2757:26)
at ReactDOMServerRenderer.read (D:\work_react\react16-demo\node_modules\.npminstall\react-dom\16.0.0\react-dom\cjs\react-dom-server.node.development
.js:2722:19)
at Object.renderToString (D:\work_react\react16-demo\node_modules\.npminstall\react-dom\16.0.0\react-dom\cjs\react-dom-server.node.development.js:29
80:25)
at Object.<anonymous> (D:/work_react/react16-demo/demo/portalsServerSide.js:29:28)
at Module._compile (module.js:571:32)
还没有找到具体的原因。