Реагировать: Как ждать, пока ссылка будет доступна, когда вставляется (отображается) во второй контейнер - PullRequest
0 голосов
/ 24 апреля 2020

РЕДАКТИРОВАТЬ: лучшее объяснение

Контекст:

Я получаю некоторый простой HTML код с третьего сервера, который я хочу

  • вставить в мое приложение React
  • изменить его

Ванильный JS подход

  • Я могу изменить строку с помощью регулярного выражения и добавить любой тег HTML с помощью id
  • Затем я могу изменить эти элементы с помощью getElementById, как обычно

Подход React

  • Я не должен использовать DOM
  • Затем я должен вставить в строку некоторые компоненты, которые имеют ссылку React внутри
  • Противоположное (вставить некоторые компоненты React как обычные HTML) было бы через ReactDOMServer.renderToString
  • Итак, когда я добавляю компоненты с помощью ReactDOM.render(), проблема заключается в том, что метод render принимает его время, так что если в следующей строке я пытаюсь использовать ссылку, которая существует во вставленном компоненте, еще нет

Вопрос

  • Как это сделать? Обычно я помещаю код в useEffect с [] зависимостями, но здесь я rendering компонент, когда приложение уже смонтировано
  • Быстрый обходной путь - просто выполнить asyn c подождите 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>
  );
}

Ответы [ 2 ]

0 голосов
/ 24 апреля 2020

Мне нужно использовать обратный вызов ref , но инкапсулировать его в useCallback, чтобы убедиться, что он перерисовывается только с указанными зависимостями (то есть, без []), так что он выполняется только тогда, когда компонент изменения (как объяснено здесь )

коды и поле

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>
  );
}
0 голосов
/ 24 апреля 2020

useEffect с пустым массивом зависимостей выполняется после первого рендеринга, поэтому вы получите ссылку DOM в обратном вызове:

const htmlString = '<div id="container">Hello</div>';

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

  useEffect(() => {
    if (myRef.current) {
      myRef.current.textContent = 'whats up';
    }
    console.log(myRef.current);
  }, []);

  return (
    <div>
      <div ref={myRef} dangerouslySetInnerHTML={{ __html: htmlString }} />
      <div dangerouslySetInnerHTML={{ __html: htmlString }} />
    </div>
  );
}

/* App renders:
whats up
Hello
*/

Edit nervous-glade-8rtxb

...