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

Ron*_*nie 22 reactjs

我正在逐步用React替换一些Backbone视图.

我的反应观点:

<div id="reactViewContent">Rendered By React</div>
Run Code Online (Sandbox Code Playgroud)

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

<div id="somestuff">
  <div id="anotherView">Other stuff not to delete</div>
  <div id="placeholderForReactView"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

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

React.render(React.createElement(MyTestReactView), document.getElementById('placeholderForReactView'));
Run Code Online (Sandbox Code Playgroud)

可能导致:

<div id="somestuff">
  <div>Other stuff not to delete</div>
  <div id="reactViewContent">Rendered By React</div>
</div>
Run Code Online (Sandbox Code Playgroud)

代替:

<div id="somestuff">
  <div>Other stuff not to delete</div>
  <div id="placeholderForReactView">
    <div id="reactViewContent">Rendered By React</div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

如果没有在Jquery重复出现,有没有正确的方法呢?

Wir*_*rie 18

您不需要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"));
Run Code Online (Sandbox Code Playgroud)


glo*_*tho 11

不幸的是,目前React无法做到这一点.它取代了您渲染的任何元素的内容.

您现在可以做的最好的事情是分别渲染React组件,然后手动改变DOM以使其达到您想要的位置.

我希望你所寻求的功能不久就会在React中提供,但还没有!


Ven*_*ryx 6

这似乎有效:

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

const myComp = MyComp({});

// when portal is "rendered", it will insert `myComp` into the specified container (document.head)
const portalThatInsertsMyCompIntoHead = ReactDOM.createPortal(myComp, document.head);

// render portal into unattached div container; portal still performs the insert-into-head as desired
ReactDOM.render(portalThatInsertsMyCompIntoHead, document.createElement("div"));
Run Code Online (Sandbox Code Playgroud)

结果:

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

不确定这个方法是否有任何负面影响,但到目前为止它似乎适合我的用法。


Ale*_*iuS 5

应该这样做:

/**
 * 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));
  });
}
Run Code Online (Sandbox Code Playgroud)

用法:

replaceNodeWithReactComponent(myHTMLelement, <MyReactComponent />);
Run Code Online (Sandbox Code Playgroud)

编辑:反应 18

由于在 React 18 中渲染发生了变化并且回调被删除,我设法将替换方法更新为以下内容:

import ReactDOM from 'react-dom/client';

/**
 * Replaces html node with react component
 * @param element
 * @param reactComponent
*/
export function replaceNodeWithReactComponent (element: HTMLElement, reactComponent: React.ReactNode) {
  const parent = document.createElement('div');
  const root = ReactDOM.createRoot(parent);

  const callback = () => {  
    // Get nodes from parent div.
    const childNodes = Array.from(parent.childNodes || []);

    // Get nodes from rendered div under parent div.
    const flatChildNodes = childNodes.reduce((newFlatChildNodes, childNode) => {
      newFlatChildNodes.push(...Array.from(childNode.childNodes || []));

      return newFlatChildNodes;
    }, []);

    // Finally replace element with our react component.
    element.replaceWith(...flatChildNodes);
  };

  // Render and callback.
  root.render(<div ref={callback}>{reactComponent}</div>);
}
Run Code Online (Sandbox Code Playgroud)

确保此 util 文件的扩展名是tsx