comunicar-se com um componente funcional fora de reação

Sep 02 2020

Eu quero ser capaz de me comunicar com meu componente de reação de fora do componente em HTML normal (necessário devido à incorporação de um componente em outro sistema).

Eu estive pesquisando sobre isso e vi conselhos que você pode adicionar componente windowadicionando um ref no elemento renderizado assim:

  ReactDOM.render(
    <Hello
      ref={(element) => {
        window.helloComponent = element;
      }}
    />,
    rootElement
  );

Mas para mim não funciona e gera este aviso:

index.js: 27 Aviso: os componentes da função não podem receber refs. As tentativas de acessar este ref falharão. Você pretendia usar React.forwardRef ()?

O componente não é adicionado ao objeto de janela, portanto, a referência não funciona a partir do botão html fora do componente react.

Tenho tentado várias maneiras com createRef () para adicionar à janela, mas não consigo descobrir. Não consigo relacionar os documentos forwardRef () à minha situação atual.

Aqui está o meu código:

const rootElement = document.getElementById("root");

if (rootElement) {
  ReactDOM.render(
    <Hello
      ref={(element) => {
        window.helloComponent = element;
      }}
    />,
    rootElement
  );
}

function Hello() {
  function alertOne() {
    alert("hi from 1");
  }
  return (
    <div>
      <h1>Hello, world! </h1> <UpdateButton />
    </div>
  );
}

function UpdateButton() {
  function alertTwo() {
    alert("hi from 2");
  }

  return <button onClick={alertTwo}> Click Me Inside React</button>;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <button onclick="window.helloComponent.alertOne()">
      Click me outside react
    </button>
    <div id="root"></div>

Gostaria de saber a técnica certa para acessar alertOne()e alertTwo()de fora de qualquer componente react, apenas de html na mesma página que o componente renderiza.

Respostas

1 95faf8e76605e973 Sep 02 2020 at 10:40

Salvando a função no objeto da janela:

const rootElement = document.getElementById("root");

if (rootElement) {
  ReactDOM.render(
    <Hello />,
    rootElement
  );
}

function Hello() {

  function alertOne() {
    alert("hi from 1");
  }
  
  window.helloComponentAlert = alertOne;
  
  return (
    <div>
      <h1>Hello, world! </h1> <UpdateButton />
    </div>
  );
}

function UpdateButton() {
  function alertTwo() {
    alert("hi from 2");
  }

  return <button onClick={alertTwo}> Click Me Inside React</button>;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>

<script>
const handleClick = () => {
  window.helloComponentAlert();
}
</script>

<button onclick="handleClick()">Click me outside react</button>
<div id="root"></div>


Abordagem orientada a eventos:

const rootElement = document.getElementById("root");

if (rootElement) {
  ReactDOM.render(
    <Hello/>,
    rootElement
  );
}

function Hello() {

  function alertOne() {
    alert("hi from 1");
  }

  React.useEffect(() => {
     window.addEventListener(
       "someEvent",
       alertOne,
       false
    );
  }, []);
  
  return (
    <div>
      <h1>Hello, world! </h1> <UpdateButton />
    </div>
  );
}

function UpdateButton() {
  function alertTwo() {
    alert("hi from 2");
  }

  return <button onClick={alertTwo}> Click Me Inside React</button>;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>

<script>
const handleClick = () => {
  var someEvent = new Event("someEvent");
  window.dispatchEvent(someEvent);
}
</script>

<button onclick="handleClick()">Click me outside react</button>
<div id="root"></div>


Abordagem orientada a eventos com passagem de dados adicionais:

const rootElement = document.getElementById("root");

if (rootElement) {
  ReactDOM.render(
    <Hello/>,
    rootElement
  );
}

function Hello() {

  function alertOne(e) {
    alert("hi from 1 " + e.detail);
  }

  React.useEffect(() => {
     window.addEventListener(
       "someEvent",
       alertOne,
       false
    );
  }, []);
  
  return (
    <div>
      <h1>Hello, world! </h1> <UpdateButton />
    </div>
  );
}

function UpdateButton() {
  function alertTwo() {
    alert("hi from 2");
  }

  return <button onClick={alertTwo}> Click Me Inside React</button>;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>

<script>
const handleClick = () => {
  var someEvent = new CustomEvent("someEvent", {detail: "SomeAdditionalData"});
  window.dispatchEvent(someEvent);
}
</script>

<button onclick="handleClick()">Click me outside react</button>
<div id="root"></div>

1 arslan2012 Sep 02 2020 at 10:21

const rootElement = document.getElementById("root");
window.alertEvent = new Event('alert');

if (rootElement) {
  ReactDOM.render(
    <Hello/>,
    rootElement
  );
}

function Hello() {
  function alertOne() {
    alert("hi from 1");
  }
  window.addEventListener('alert',alertOne);
  return (
    <div>
      <h1>Hello, world! </h1> <UpdateButton />
    </div>
  );
}

function UpdateButton() {
  function alertTwo() {
    alert("hi from 2");
  }

  return <button onClick={alertTwo}> Click Me Inside React</button>;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <button onclick="window.dispatchEvent(window.alertEvent)">
      Click me outside react
    </button>
    <div id="root"></div>

Surender Sep 02 2020 at 10:43

Aqui está um exemplo que criei em que você também pode passar alguns valores usando o padrão de assinatura de publicação de evento em javascript.

https://codesandbox.io/s/react-playground-forked-r7dfn?file=/index.js