如何在Vanilla HTML / JS中重新加载ReactJS组件?

问题描述 投票:1回答:1

这可能是一个愚蠢的问题。但实际上,我正在创建一个可在任何普通HTML / JS文件中使用的React Modal组件。我可以使用Webpack从React组件中创建一个bundle.js文件,然后可以将其注入Vanilla HTML文件的div标签中,如下所示:

<div id="my-modal-target"></div>
<script src="bundle.js"></script>

由于我正在尝试创建模式,所以发生的事情是,每当用户单击“退出”时,我的React组件将有条件地将模式隐藏。但是,我试图弄清楚如何通过单击目标Vanilla HTML文件中的按钮来重新加载React组件。我将对我应该如何进行提出任何建议。这是我尝试过的一些东西:

  • 使用“ ReactDOM.unmountComponentAtNode(document.getElementById(DIV_TAG_NAME));”强制从目标HTML的div标签中卸载React组件,然后使用JQuery重新加载div标签。但是,这似乎会导致CORS问题,使我无法重新加载div标签。此外,这在React方面似乎并不是一个好习惯。
  • 在Vanilla HTML文件中单击按钮时,它会将prop传递到React组件中。但是,这似乎不起作用,因为仅在首次加载React组件时才传递道具。换句话说,如果更改Vanilla HTML文件中的props,则不会影响React组件。

非常感谢您的帮助!

javascript jquery html reactjs dom
1个回答
1
投票

有多种方法可以完成React / non-React通信。

使用自定义事件

虽然每种方法都有优点和缺点,但是这是与框架无关的优点。您也可以对Vue组件和vanilla js执行相同的操作。缺点是您需要找到一种以干净的方式管理和记录事件的方法,否则您的应用程序可能很快变得难以维护。


在组件内部,您需要创建并监听自定义事件。然后,您可以从任何地方分派它,组件将捕获它并进行相应的更新。

const OPEN_EVENT_NAME = 'open';
const CLOSE_EVENT_NAME = 'close';

const container = document.querySelector('#app');

class App extends React.Component {
  constructor(props) {
    super(props);
 
    this.state = {
      open: true,
    }
    
    // Bind the "open" and "close" events to their respective functions
    container.addEventListener(OPEN_EVENT_NAME, this.openModal);
    container.addEventListener(CLOSE_EVENT_NAME, this.closeModal);
  }
  
  openModal = () => {
    this.setState({ open: true });
  }
  
  closeModal = () => {
    this.setState({ open: false });
  }

  render() {
    return (
      <div>The modal is {this.state.open ? 'open' : 'closed'}</div>
    )
  };
}

ReactDOM.render(<App />, container);

// Create custom events
const openEvent = new Event(OPEN_EVENT_NAME);
const closeEvent = new Event(CLOSE_EVENT_NAME);

// Create events dispatchers
const openModal = () => container.dispatchEvent(openEvent);
const closeModal = () => container.dispatchEvent(closeEvent);

// Dispatch events on buttons click
document.querySelector('#open-btn').addEventListener('click', openModal);
document.querySelector('#close-btn').addEventListener('click', closeModal);
body {
  font-family: 'system-ui';
  padding: 12px;
}

h2 {
  font-weight: bold;
  margin: 0;
  margin-bottom: 6px;
}

hr {
  margin: 12px 0;
}
<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>

<h2>
This is React
</h2>
<div id="app"></div>

<hr>

<h2>
This is not React
</h2>

<button id="open-btn">
Open modal
</button>

<button id="close-btn">
Close modal
</button>

使用参考

引用通常用于访问React组件的底层DOM元素。

它们还可以用于将组件附加到窗口对象,从而访问其状态并公开其方法。

此方法不太容易出错,因为您使用与组件相同的语言(状态,方法等),但这也是不利的一面,因为这意味着您组件的最终用户对React有所了解,这可能并非如此。


这是方法,thanks to this article

class App extends React.Component {
  constructor(props) {
    super(props);
 
    this.state = {
      open: true,
    }
  }
  
  openModal = () => {
    this.setState({ open: true });
  }
  
  closeModal = () => {
    this.setState({ open: false });
  }

  render() {
    return (
      <div>The modal is {this.state.open ? 'open' : 'closed'}</div>
    )
  };
}

ReactDOM.render(<App ref={myComponent => window.myComponent = myComponent} />, document.querySelector('#app'));
body {
  font-family: 'system-ui';
  padding: 12px;
}

h2 {
  font-weight: bold;
  margin: 0;
  margin-bottom: 6px;
}

hr {
  margin: 12px 0;
}
<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>

<h2>
This is React
</h2>
<div id="app"></div>

<hr>

<h2>
This is not React
</h2>

<button onclick="window.myComponent.openModal()">
Open modal
</button>

<button onclick="window.myComponent.closeModal()">
Close modal
</button>

-更新-

由于您正在使用React钩子,并且您无法引用功能组件,因此我不建议您使用方法2。

[我建立了一个迷你示例,说明如何实现方法1(使用事件与React进行通信)。

如上所述,这为最终用户提供了更好的API,并且可能是两者中最干净的解决方案。

This demo is available here.

© www.soinside.com 2019 - 2024. All rights reserved.