Reaction:在第二个容器中插入(呈现)REF时如何等待,直到REF可用

编辑:更好的解释

上下文:

我从第三台服务器收到一些普通的HTML代码,我希望

  • 在我的Reaction应用程序中插入
  • 修改

普通JS方法

  • 我可以使用正则表达式修改字符串,并使用id
  • 添加任何HTML标记
  • 然后我可以像往常一样通过getElementById修改这些元素

反应方法

  • 我不应该使用DOM
  • 然后我应该在字符串中插入一些内部有Reaction引用的组件
  • 相反(将一些Reaction组件作为纯HTML插入)将通过ReactDOMServer.renderToString
  • 因此,当我使用ReactDOM.render()注入组件时,问题是render方法很耗时,因此如果在下一行尝试使用插入的组件中存在的ref,它还不在那里

问题

  • 怎么做?通常我会将代码放在具有[]依赖项的useEffect中,但在这里我是rendering应用程序已经挂载的组件
  • 一种快速的解决方法是只进行500毫秒的异步等待,然后我就可以访问ref,但肯定会有更好的

此代码失败,因为当呈现ref时,它仍然不可用,因此ref.current是未定义的

我怎么能等它?

codesandbox

编辑:我提供了可通过直接DOM运行的代码,我认为应该避免

import React, { useRef, useEffect } from "react";
import ReactDOM from "react-dom";

export default function App() {
  const myref = useRef();

  useEffect(() => {
    const Com = () => <div ref={myref}>hello</div>;
    ReactDOM.render(<Com />, document.getElementById("container"));
    console.log(myref.current); // undefined
    document.getElementById('container').textContent = "direct DOM works"

   // the next line fails since the ref is not yet available
   // myref.current.textContent = "but this REF is not available"; // fails
  }, []);

  const plainhtml = '<div><div id="container"></div><div>some more content</div><div id="another">even more content</div></div>'; // this is some large HTML fetched from an external server

  return (
    <div>
      <h1>Hello CodeSandbox</h1>
      <div dangerouslySetInnerHTML={{ __html: plainhtml }} />
    </div>
  );
}

解决方案

我需要使用callback ref,但将其封装在useCallback中,以确保它只与所指示的依赖项一起重新呈现(即无[]),这样它只在组件更改时执行(如here所述)

codesandbox

import React, { useEffect, useCallback } from "react";
import ReactDOM from "react-dom";

export default function App() {
  const measuredRef = useCallback(node => {
    if (node !== null) {
      node.textContent = "useCallback DOM also works";
    }
  }, []);

  useEffect(() => {
    const Com = () => <div ref={measuredRef}>hello</div>;
    ReactDOM.render(<Com />, document.getElementById("container"));
    document.getElementById("container").textContent = "direct DOM works";
  }, []);

  const plainhtml = '<div id="container"></div>';

  return (
    <div>
      <h1>Hello CodeSandbox</h1>
      <div dangerouslySetInnerHTML={{ __html: plainhtml }} />
    </div>
  );
}

相关文章