Javascript 反应如何等待组件/页面呈现以调用函数

Javascript 反应如何等待组件/页面呈现以调用函数,javascript,reactjs,Javascript,Reactjs,我需要修改我在这里返回的第一个div的data scroll属性。问题似乎是种族危险-active为空,因为dom尚未加载。我该怎么处理?异步/等待?我不是在质疑什么,也不会得到回应。如何等待直到呈现标头 这将生成TypeError:无法读取null的属性“dataset”: import { Link } from 'react-router-dom'; import * as ROUTES from '../constants/routes'; export default functio

我需要修改我在这里返回的第一个div的data scroll属性。问题似乎是种族危险-active为空,因为dom尚未加载。我该怎么处理?异步/等待?我不是在质疑什么,也不会得到回应。如何等待直到呈现标头

这将生成TypeError:无法读取null的属性“dataset”:

import { Link } from 'react-router-dom';
import * as ROUTES from '../constants/routes';

export default function Header() {
  const active = document.getElementById('navbar');

  const debounce = (fn) => {
    let frame;
    return (...params) => {
      if (frame) {
        cancelAnimationFrame(frame);
      }
      frame = requestAnimationFrame(() => {
        fn(...params);
      });
    };
  };
  const storeScroll = () => {
    if (window.scrollY > 80) {
      active.dataset.scroll = window.scrollY;
    }
    if (window.scrollY <= 80) {
      active.dataset.scroll = 0;
    }
  };

  // Listen for new scroll events
  document.addEventListener('scroll', debounce(storeScroll), { passive: true });

  // Update scroll position for first time
  storeScroll();
  return (
    <div id="navbar" data-scroll="0">
      <header className="fixed flex top-0 scroll:bg-blue-500 bg-transparent items-center justify-center p-5 w-full">
        <div className="container mx-auto max-w-screen-lg h-full">
          <div className="flex justify-between h-full">
            <div className="text-black text-center flex items-center align-items cursor-pointer">
              <h1 className="flex justify-center w-full">
                <Link to={ROUTES.TEST} className="font-bold text-lg" aria-label="home">
                  HOME
                </Link>
              </h1>
            </div>
          </div>
        </div>
      </header>
    </div>
  );
}
从'react router dom'导入{Link};
从“../constants/ROUTES”导入*作为路由;
导出默认函数头(){
const active=document.getElementById('navbar');
常数去盎司=(fn)=>{
让框架;
返回(…参数)=>{
如果(帧){
取消动画帧(帧);
}
frame=requestAnimationFrame(()=>{
fn(…参数);
});
};
};
const storeScroll=()=>{
如果(window.scrollY>80){
active.dataset.scroll=window.scrollY;
}

如果(window.scrollY您可以使用
useffect
挂钩:

import { useEffect } from 'react'; 

useEffect(()=>{
  // what should happen after the initial render
  const active = document.getElementById('navbar');
  active.setAttribute("data-scroll", <your_value>)
},[]);
从“react”导入{useffect};
useffect(()=>{
//在初始渲染之后应该发生什么
const active=document.getElementById('navbar');
active.setAttribute(“数据滚动”,)
},[]);

您需要使用
ref
来“捕获”DOM元素

const debounce=(fn)=>{
让框架;
返回(…参数)=>{
如果(帧){
取消动画帧(帧);
}
frame=requestAnimationFrame(()=>{
fn(…参数);
});
};
};
常量storeScroll=(元素)=>()=>{
如果(window.scrollY>80){
active.dataset.scroll=window.scrollY;
}
如果(window.scrollY{
如果(!元素){
返回null;
}
addEventListener('scroll',debounce(storeScroll(element)),{passive:true});
storeScroll(元素);
}
返回(
...
);
}
尽管可以使用
document.getElementById
,但React中不鼓励使用它,而获取DOM元素引用的惯用方法是通过引用

从组件中拉出函数并不是绝对必要的,只是我推荐的一种做法

  • 仅绑定useEffect中的事件
  • 同样,您可以在useffect中访问导航栏

     useEffect(() => {
         const active = document.getElementById('navbar');
     }, [])
    

  • 在react中直接以底层DOM为目标不是一个好的做法。我们可以使用
    ref
    来实现这一点

    另外,您正在添加一个
    eventListener
    ,当组件卸载时,它不会被正确删除。因此,为了确保在渲染完成时拥有该元素,您可以使用
    useffect
    钩子,该钩子保证在绘制DOM之后运行它

    因此,您需要将eventListener代码移动到useEffect挂钩中。下面是使用
    Ref
    useEffect
    更新的代码

    import {Link} from 'react-router-dom';
    import * as ROUTES from '../constants/routes';
    import {useRef, useEffect} from 'react';
    
    export default function Header() {
      const navbarRef = useRef();
    
      const debounce = (fn) => {
        let frame;
        return (...params) => {
          if (frame) {
            cancelAnimationFrame(frame);
          }
          frame = requestAnimationFrame(() => {
            fn(...params);
          });
        };
      };
    
      const storeScroll = () => {
        if (window.scrollY > 80) {
          navbarRef.current.dataset.scroll = window.scrollY;
        }
        if (window.scrollY <= 80) {
          navbarRef.current.dataset.scroll = 0;
        }
      };
    
      useEffect(() => {
        // Update scroll position for first time
        storeScroll();
        
        // attact the event listener
        window.addEventListener('scroll', debounce(storeScroll), {passive: true});
        
        // remove the event listener when the component is unmounted
        return () =>
          window.removeEventListener('scroll', debounce(storeScroll), {
            passive: true,
          });
      }, []);
    
      return (
        <div id="navbar" ref={navbarRef} data-scroll="0">
          <header className="fixed flex top-0 scroll:bg-blue-500 bg-transparent items-center justify-center p-5 w-full">
            <div className="container mx-auto max-w-screen-lg h-full">
              <div className="flex justify-between h-full">
                <div className="text-black text-center flex items-center align-items cursor-pointer">
                  <h1 className="flex justify-center w-full">
                    <Link
                      to={ROUTES.TEST}
                      className="font-bold text-lg"
                      aria-label="home"
                    >
                      HOME
                    </Link>
                  </h1>
                </div>
              </div>
            </div>
          </header>
        </div>
      );
    }
    
    从'react router dom'导入{Link};
    从“../constants/ROUTES”导入*作为路由;
    从“react”导入{useRef,useffect};
    导出默认函数头(){
    const navbarRef=useRef();
    常数去盎司=(fn)=>{
    让框架;
    返回(…参数)=>{
    如果(帧){
    取消动画帧(帧);
    }
    frame=requestAnimationFrame(()=>{
    fn(…参数);
    });
    };
    };
    const storeScroll=()=>{
    如果(window.scrollY>80){
    navbarRef.current.dataset.scroll=window.scrollY;
    }
    如果(window.scrollY{
    //第一次更新滚动位置
    storeScroll();
    //附加事件侦听器
    addEventListener('scroll',debounce(storeScroll),{passive:true});
    //卸载组件时删除事件侦听器
    return()=>
    window.removeEventListener('scroll',debounce(storeScroll){
    被动:是的,
    });
    }, []);
    返回(
    家
    );
    }
    
    import {Link} from 'react-router-dom';
    import * as ROUTES from '../constants/routes';
    import {useRef, useEffect} from 'react';
    
    export default function Header() {
      const navbarRef = useRef();
    
      const debounce = (fn) => {
        let frame;
        return (...params) => {
          if (frame) {
            cancelAnimationFrame(frame);
          }
          frame = requestAnimationFrame(() => {
            fn(...params);
          });
        };
      };
    
      const storeScroll = () => {
        if (window.scrollY > 80) {
          navbarRef.current.dataset.scroll = window.scrollY;
        }
        if (window.scrollY <= 80) {
          navbarRef.current.dataset.scroll = 0;
        }
      };
    
      useEffect(() => {
        // Update scroll position for first time
        storeScroll();
        
        // attact the event listener
        window.addEventListener('scroll', debounce(storeScroll), {passive: true});
        
        // remove the event listener when the component is unmounted
        return () =>
          window.removeEventListener('scroll', debounce(storeScroll), {
            passive: true,
          });
      }, []);
    
      return (
        <div id="navbar" ref={navbarRef} data-scroll="0">
          <header className="fixed flex top-0 scroll:bg-blue-500 bg-transparent items-center justify-center p-5 w-full">
            <div className="container mx-auto max-w-screen-lg h-full">
              <div className="flex justify-between h-full">
                <div className="text-black text-center flex items-center align-items cursor-pointer">
                  <h1 className="flex justify-center w-full">
                    <Link
                      to={ROUTES.TEST}
                      className="font-bold text-lg"
                      aria-label="home"
                    >
                      HOME
                    </Link>
                  </h1>
                </div>
              </div>
            </div>
          </header>
        </div>
      );
    }