React.render 替换容器而不是插入

IT技术 reactjs
2021-04-19 02:30:51

我正在逐渐用 React 替换一些 Backbone 视图。

我的react视图:

<div id="reactViewContent">Rendered By React</div>

我需要在其他 html 元素下方呈现 React 视图而不替换它们。

<div id="somestuff">
  <div id="anotherView">Other stuff not to delete</div>
  <div id="placeholderForReactView"></div>
</div>

我希望我的方法可以替换占位符而不是插入它,以便:

React.render(React.createElement(MyTestReactView), document.getElementById('placeholderForReactView'));

可能导致:

<div id="somestuff">
  <div>Other stuff not to delete</div>
  <div id="reactViewContent">Rendered By React</div>
</div>

代替:

<div id="somestuff">
  <div>Other stuff not to delete</div>
  <div id="placeholderForReactView">
    <div id="reactViewContent">Rendered By React</div>
  </div>
</div>

如果不重复出现在 Jquery 上,是否有正确的方法来做到这一点?

5个回答

您不需要 jQuery 来解决此问题。

您只需要渲染到一个临时 DIV 并提取内容并替换现有元素。我添加了id="destination"以便可以轻松地从临时元素中检索元素。

var Hello = React.createClass({
    render: function() {
        return <div id="destination">Hello {this.props.name}</div>;
    }
});

// temporary render target
var temp = document.createElement("div");
// render
React.render(<Hello name="World" />, temp);
// grab the container
var container = document.getElementById("container");
// and replace the child
container.replaceChild(temp.querySelector("#destination"), document.getElementById("destination"));
这在使用 React Hot Loader 之类的东西时是有问题的。在某些情况下,例如更改组件的结构时,浏览器会出现异常。
2021-06-12 02:30:51
警告,它可能会破坏事情,jsfiddle.net/crl/arshc5nk/7相比jsfiddle.net/crl/arshc5nk/8 mouseOver 不再工作,除非您避免内联事件并执行jsfiddle.net/crl/arshc5nk/9
2021-06-22 02:30:51

不幸的是,目前 React 无法做到这一点。它会替换您渲染到的任何元素的内容。

你现在能做的最好的事情是单独渲染 React 组件,然后手动改变 DOM 以将它放到你想要的地方。

我希望您寻求的功能不久将在 React 中可用,但还没有!

那应该这样做:

 * Replaces html node with react component
 * @param element
 * @param reactComponent
 */
export function replaceNodeWithReactComponent (element: HTMLElement, reactComponent: any) {
  const parent = document.createElement('div');
  ReactDOM.render(reactComponent, parent, () => {
    element.replaceWith(...Array.from(parent.childNodes));
  });
}

用法:

replaceNodeWithReactComponent(myHTMLelement, <MyReactComponent />);

这似乎有效:

const linkEl = <link href="https://fonts.googleapis.com/css?family=Cinzel&display=swap" rel="stylesheet"/>;

// portal will do actual adding-to-head
const linkElAsDirectChildOfHead = ReactDOM.createPortal(linkEl, document.head);

// render stub into never-added container
ReactDOM.render(linkElAsDirectChildOfHead, document.createElement("div"));

结果:

请注意,根据需要,它不会删除 document.head 中的其他子项。

不确定这种方法是否有任何负面影响,但乍一看似乎有效。

扩展@WiredPrairie 的解决方案,使用占位符元素的问题是 React 似乎从父节点获取事件,所以如果父节点不在 DOM 中的正确位置,则事件不会触发(无论如何,这是我的理论) .

要解决此问题,您可以使用实际元素父元素,但通过保留父子元素的副本来保留原始 DOM,然后稍后重新添加它们,大致如下:

https://jsfiddle.net/n41dzLx2/

const el = document.querySelector("#app");
const parent = el.parentNode;
const oldChildren = Array.from(parent.childNodes);

ReactDOM.render(
  <App />, 
  parent, 
  () => {
    const newChildren = Array.from(parent.childNodes);
    parent.replaceChildren(...oldChildren);
    el.replaceWith(...Array.from(newChildren));
  }
)

这在大多数情况下都有效,但如果组件中的根元素发生变化,React 元素将移动到父元素的末尾。