Как управлять активным взаимодействием между двумя независимыми приложениями react?

#reactjs #react-context

Вопрос:

У меня есть приложение react, которое должно отображаться в двух разных корневых элементах DOM. Каков наилучший способ обмена данными между ними на основе изменений внутри одного из них? Похоже, я не могу обернуть два приложения в поставщика контекста или использовать способ состояния/эффекта/обратного вызова для связи между ними.

 ReactDOM.render(
      <ReactApp1 componentData={}/>
      , rootElement1
); 
ReactDOM.render(
      <ReactApp2 componentData={}/>
      , rootElement2 
);
 

Ответ №1:

Если единственная причина, по которой вы разделяете вещи, заключается в том, что вам нужно поместить контент в два несвязанных узла dom, вы можете добиться этого с помощью портала вместо двух вызовов ReactDOM.render. Таким образом, вы можете использовать стандартные реквизиты и/или контекст для передачи данных между вашими компонентами.

 ReactDOM.render(
  <App />
  rootElement1
)

const App = () => {
  const rootElement2 = /* some code to select rootElement2 from the page. eg, document.getElementById('someId') */

  return (
    <>
      <ReactApp1 componentData={/*...*/}/>
      {React.createPortal(<ReactApp2 componentData={/*...*/} />, rootElement2)}
    </>

  )
}
 

Если это невозможно, и вам нужны совершенно отдельные вызовы для ReactDOM.render, то, скорее всего, вам нужно будет создать какой-нибудь паб/суб-код и заставить приложения отправлять сообщения друг другу. Если у вас есть любимая библиотека для источников событий, вы можете использовать ее, или если вы хотите создать свою собственную, она может выглядеть примерно так:

 // These lines will probably be in their own file
const subscriptions = [];
export const subscribe = (callback) => {
  subscriptions.push(callback);
  const unsubscribe = () => {
    const i = subscriptions.findIndex(callback);
    subscriptions.splice(i, 1);
  }
  return unsubscribe
}
export const publish = (data) => {
  [...subscriptions].forEach(callback => callback(data));
}

// Used like:

const ReactApp1 = () => {
  const [count, setCount] = useState(0);
  useEffect(() => {
    // Listen to messages
    const unsubscribe = subscribe((data) => {
      setCount(data);
    });
    return unsubscribe;
  }, []);

  return <div onClick={() => {
    publish(count   1);
  }}/>
}
 

Комментарии:

1. Спасибо @nicholas-tower. Порталы, похоже, правильный путь. Дадим ему шанс.