【问题标题】:ReactJS - Detect third-party DOM insert using Mutation ObserverReactJS - 使用 Mutation Observer 检测第三方 DOM 插入
【发布时间】:2021-06-25 06:35:29
【问题描述】:

在组件内部,第三方 JavaScript 库在 React 渲染后将一些内容注入特定的 DIV (voice-service)。当使用 Mutation Observer 注入 DOM 时,我想在该 DIV (voice-service) 上添加或删除一些 CSS 类,例如 -

当 DOM 注入时 -

<div id="maxVoiceContainer" class="voice-service service--active">
 // third-party content
</div>

当 DOM 未注入时 -

<div id="maxVoiceContainer" class="voice-service service--inactive">
// third-party content
</div>

heroVoice 组件:

import React, { useRef, useState, useEffect } from 'react';

const heroVoice = (props) => {

    const elementRef = useRef();
    const [voiceAvailability, setVoiceAvailability] = useState(false);

    useEffect(() => {
        const config = { attributes: false, characterData: false, childList: true, subtree: true, attributeOldValue: false, characterDataOldValue: false };
        const observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                const newNodes = mutation.addedNodes;
                newNodes.forEach(node => {
                    if (node.classList && node.classList.contains('pocket-sphinx-container')) {
                        setVoiceAvailability(status => !status);
                    }
                });
            });
        });
        observer.observe(elementRef.current, config);
    }, []);

    return (
        <div
            ref={elementRef}
            id="maxVoiceContainer"
            className={`voice-service ${voiceAvailability ? ' service--active' : 'service--inactive'}`}
        >
          // third-party content
        </div>
    );
}

export default heroVoice;

想知道-

  1. 我需要断开观察者的连接吗?
  2. 看起来不错?最佳做法?
  3. 另外,我不想在状态更新时重新渲染!

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    问:我需要断开观察者的连接吗? 它不是直接需要的,但我建议使用mutationObserver.disconnect() 方法,因为您在 ComponentDidMount 上被调用一次。 第二个参数处的空数组表示它。 Ref

    看起来不错?最佳实践? 是的,看起来相当不错。避免嵌套 forEach。最好先使用 map 而不是 forEach

     mutations.map(mutation => mutation.addedNodes).forEach(node => {
      if (node.classList && node.classList.contains('pocket-sphinx-container')) {
        setVoiceAvailability(status => !status);
      }
     });

    另外,我不想在状态更新时重新渲染! React 的生命周期就是为此而构建的。有两种可能性。首先,您可以使用 Redux 或创建一个在 forEach 中设置的局部变量。但一般不要在 forEach 中使用 setState 钩子

    【讨论】:

    • 谢谢。在我上面的例子中放置断开方法有什么建议吗?
    • 在观察完一切之后。我不知道您到底在获取什么,但您可以设置一个超时,在 5000 毫秒后断开连接
    猜你喜欢
    • 2015-04-20
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    • 2012-10-27
    相关资源
    最近更新 更多