【问题标题】:How to Re-load ReactJS Component in Vanilla HTML / JS?如何在 Vanilla HTML / JS 中重新加载 ReactJS 组件?
【发布时间】:2020-07-18 01:08:34
【问题描述】:

这可能是一个愚蠢的问题。但本质上,我正在创建一个可用于任何普通 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 组件时才会传入 props。也就是说,如果更改 Vanilla HTML 文件中的 props,不会影响 React 组件。

提前非常感谢您的帮助!

【问题讨论】:

    标签: javascript jquery html reactjs dom


    【解决方案1】:

    您可以通过多种方式完成 React/非 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>

    使用参考

    Refs 通常用于访问 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.

    【讨论】:

    • 嗨,朱利安。我尝试了“参考”示例。你知道我如何将它用于 React Hooks 吗?现在,我有错误“功能组件不能被赋予参考”。
    • 我认为这不适用于这种情况,因为正如您所见,您不能像使用类组件那样将 refs 与功能组件一起使用。如果我要设计这样一个使用 React 作为视图层的库,我会添加一个包装 javascript 类,它可以作为一个更好的 API 来与组件交互。我用这种实现的例子更新了我的答案。
    猜你喜欢
    • 2021-03-09
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 1970-01-01
    • 2018-04-24
    • 1970-01-01
    相关资源
    最近更新 更多