Javascript 检测生命周期方法或挂钩中的页面上是否存在非react元素

Javascript 检测生命周期方法或挂钩中的页面上是否存在非react元素,javascript,reactjs,intercom,Javascript,Reactjs,Intercom,我在尝试将第三方产品巡更(Intercom)与react应用程序集成时遇到了一个问题。没有办法以编程方式结束我的旅行 基本上,我需要一个道具,无论是否存在某个非react DOM元素,它都可以在react应用程序中更改。我需要能够在hook或componentdiddupdate中判断DOM中是否存在某个非React元素 我不知道该怎么办,因为很明显,当这个巡演开始和结束时,就react而言,状态和道具都没有变化 有没有一种方法可以将类似于document.getElementById(“产品巡

我在尝试将第三方产品巡更(Intercom)与react应用程序集成时遇到了一个问题。没有办法以编程方式结束我的旅行

基本上,我需要一个道具,无论是否存在某个非react DOM元素,它都可以在react应用程序中更改。我需要能够在hook或
componentdiddupdate
中判断DOM中是否存在某个非React元素

我不知道该怎么办,因为很明显,当这个巡演开始和结束时,就react而言,状态和道具都没有变化

有没有一种方法可以将类似于
document.getElementById(“产品巡更覆盖的Id”)
的结果包装成一个组件作为道具?有没有办法让我用钩子来看着它

理想情况下

componentDidUpdate(){
   if(elementExists){
      //Do stuff that needs to happen while tour is on
   }
   if(!elementExists){
       //do app stuff to end the tour
   }
}

//OR

useEffect(()=>{
   //do stuff conditional on element's existence
},[elementExists])


你能用一会儿吗

useEffect(()=>{
   while (document.getElementById('theTour') !== null) {
     // do stuff
   }
   // do cleanup
})

这样做的简单方法是准备一个函数,该函数接收HTML元素,并返回一个函数,该函数接收回调作为参数(返回其他函数的函数,以达到纯度)。返回函数的结果是一个具有回调集的新MutationObserver

const observeTarget = target => callback => {
  const mutationObserver = new MutationObserver(callback);
  mutationObserver.observe(target, { childList: true });
}
在非react文件中,您可以向该函数提供一个HTML元素,该元素是您要调查的第三方元素的容器

然后导出函数,您可以在react组件中使用它

export const observeProductTourOverlay = observeTarget(containerOfProductTourOverlay);
然后在React组件中,您可以使用useEffect钩子并使用函数

const checkIFMyCompExists = () => !!document.querySelector("#my-component");

export const FromOutside = () => {
  const [elementExists, setElementExist] = useState(checkIFMyCompExists());
  const [indicator, setIndicator] = useState(3);
  useEffect(() => {
    observeProductTourOverlay((mutationRecord, observer) => {
      const doesExist = checkIFMyCompExists();
      setElementExist(doesExist);
      // this will fire every time something inside container changes
      // (i.e. a child is added or removed)
    });

    // garbage collector should take care of mutationObserver in a way there are no memory leaks, so no need to disconnect it on compoment unmouting.
  }, []);

  useEffect(() => {
    setIndicator(elementExists);
    //do stuff when elementExistance changes
  }, [elementExists]);
  return (
    <div>
      <div>{"my component has been added: " + indicator}</div>
    </div>
  );
};
const checkIFMyCompExists=()=>!!document.querySelector(“我的组件”);
从外部导出常量=()=>{
const[elementExists,setelementexists]=useState(checkIFMyCompExists());
const[indicator,setIndicator]=使用状态(3);
useffect(()=>{
observeProductTourOverlay((变异记录,观察者)=>{
const doesExist=checkIFMyCompExists();
setElementExist(性别歧视);
//每当容器内的内容发生变化时,该命令就会触发
//(即添加或删除儿童)
});
//垃圾收集器应该以一种不存在内存泄漏的方式来处理mutationObserver,因此无需在组件卸载时断开它的连接。
}, []);
useffect(()=>{
setIndicator(elementExists);
//当elementExistance发生变化时做一些事情
},[elementExists]);
返回(
{“我的组件已添加:“+指示器}”
);
};

在此处找到工作演示:

Ok。看起来它对子列表中的更改的响应很好。但是它在几秒钟后抛出这个错误`TypeError:cannotreadproperty'getElementByID'为undefined`对于这一行
constdoesexist=!!mutationRecord.target.getElementByID(“产品巡更覆盖的Id”)
我正在使用
document.body
作为
observeTarget
参数,因为它是巡更的唯一父项。解决方案适用于不是
的父项和子项或
body
的直接子项的父项和子项。第三方产品巡更是
document.body
的直接子产品。还尝试了
document.body | | document.documentElement
,这导致未观察到任何更改。我得到初始的
元素exists:false
但没有后续的更改。try const doesExist=!!document.getElementByID(“产品巡更覆盖的Id”);稍后我将实现整个解决方案,并将粘贴到此处