当对象不在 DOM 中时,如何解决无法在 React 挂钩中读取 null 的 querySelector
How to fix cannot read querySelector of null in React hook when Object is not in DOM
components/VideoPlayer.js
import '../../style/VideoPlayer/VideoPlayer.css';
const VideoPlayer = () => {...some code...return(...some code...)} export default VideoPlayer
VideoContainer.js
import VideoPlayer from "../../VideoPlayer"
import useVideoPlayer from "../../../hooks/useVideoPlayer"
const VideoContainer = ({ info }) => {
const { playPause, toggleFullScreen, fullscreen } = useVideoPlayer()
return (
<React.Fragment>
<div>
...
{/* {playPause == true ? (
<div><VideoPlayer/></div>)
: null} */}
{fullscreen && <div id="testing"><VideoPlayer src={info.somesrc} title={info.sometitle} /></div>}
{/* <div id="testing"><VideoPlayer src={info.somesrc} title={info.sometitle} /></div> */}
...
</div>
</React.Fragment>
)
import React, { useState, useEffect, useRef, useLayoutEffect } from 'react'
const useVideoPlayer = () => {
const [playVideo, setPlayVideo] = useState(false)
const [fullscreen, setFullscreen] = useState(false)
useEffect(() => {
const controlsContainer = document.querySelector('.video-container .controls-container');
const playPauseButton = document.querySelector('.video-container .controls button.play-pause');
const pauseButton = playPauseButton.querySelector('.paused'); // typeError cannot read property querySelector of null
...some other queryselectors...
}, []);
const displayControls = () => {
let controlsTimeout;
const controlsContainer = document.querySelector('.video-container .controls-container');
...
}
const playPause= () => {
const video = document.querySelector('.video-container video');
if (...) {
video.play();
setPlayVideo(true);
} else (...) {
video.pause();
setPlayVideo(false);
};
}
const toggleFullScreen = () => {
const videoContainer = document.querySelector('.video-container');
if (...) {setFullscreen(true)} else (...) {setFullscreen(false)};
}
...
document.addEventListener('fullscreenchange', () => {
...
}
const video = document.querySelector('.video-container video');
video && (video.addEventListener('timeupdate', () => {
...
}
...a dozen other addEventListeners for different elements fetched by querySelectors...
return { playPause, toggleFullScreen, fullscreen }
}
export default useVideoPlayer;
我正在将 playPause
、toggleFullscreen
函数和 fullscreen
reactcontext 从 useVideoPlayer
挂钩传回反应容器。
我使用 &&
并检查 fullscreen
是真还是假以呈现 <VideoPlayer/>
或不
当组件不在 DOM 中时,useVideoPlayer
挂钩不起作用,我该如何解决?
Uncaught TypeError: Cannot read property 'querySelector' of null
at eval (useVideoPlayer.js:41)
at commitHookEffectListMount (react-dom.development.js:19731)
at commitPassiveHookEffects (react-dom.development.js:19769)
at HTMLUnknownElement.callCallback (react-dom.development.js:188)
at Object.invokeGuardedCallbackDev (react-dom.development.js:237)
at invokeGuardedCallback (react-dom.development.js:292)
at flushPassiveEffectsImpl (react-dom.development.js:22853)
at unstable_runWithPriority (scheduler.development.js:653)
at runWithPriority (react-dom.development.js:11039)
at flushPassiveEffects (react-dom.development.js:22820)
我试过 useLayoutEffect
,通过 useRef(null)
并包装在 if (containerRef.current) {}
中,但没有区别
您需要在尝试使用之前检查该元素是否存在:
const pauseButton = playPauseButton && playPauseButton.querySelector('.paused');
如果您想要更具可扩展性的东西,您可以在 VideoContainer
中显式控制它是否呈现,然后将其传递给您的挂钩:
const VideoContainer = ({ info }) => {
const [mounted, setMounted] = useState(false)
const { playPause, toggleFullScreen, fullscreen } = useVideoPlayer(mounted)
return (
...
{mounted ? <VideoPlayer/> : null}
components/VideoPlayer.js
import '../../style/VideoPlayer/VideoPlayer.css';
const VideoPlayer = () => {...some code...return(...some code...)} export default VideoPlayer
VideoContainer.js
import VideoPlayer from "../../VideoPlayer"
import useVideoPlayer from "../../../hooks/useVideoPlayer"
const VideoContainer = ({ info }) => {
const { playPause, toggleFullScreen, fullscreen } = useVideoPlayer()
return (
<React.Fragment>
<div>
...
{/* {playPause == true ? (
<div><VideoPlayer/></div>)
: null} */}
{fullscreen && <div id="testing"><VideoPlayer src={info.somesrc} title={info.sometitle} /></div>}
{/* <div id="testing"><VideoPlayer src={info.somesrc} title={info.sometitle} /></div> */}
...
</div>
</React.Fragment>
)
import React, { useState, useEffect, useRef, useLayoutEffect } from 'react'
const useVideoPlayer = () => {
const [playVideo, setPlayVideo] = useState(false)
const [fullscreen, setFullscreen] = useState(false)
useEffect(() => {
const controlsContainer = document.querySelector('.video-container .controls-container');
const playPauseButton = document.querySelector('.video-container .controls button.play-pause');
const pauseButton = playPauseButton.querySelector('.paused'); // typeError cannot read property querySelector of null
...some other queryselectors...
}, []);
const displayControls = () => {
let controlsTimeout;
const controlsContainer = document.querySelector('.video-container .controls-container');
...
}
const playPause= () => {
const video = document.querySelector('.video-container video');
if (...) {
video.play();
setPlayVideo(true);
} else (...) {
video.pause();
setPlayVideo(false);
};
}
const toggleFullScreen = () => {
const videoContainer = document.querySelector('.video-container');
if (...) {setFullscreen(true)} else (...) {setFullscreen(false)};
}
...
document.addEventListener('fullscreenchange', () => {
...
}
const video = document.querySelector('.video-container video');
video && (video.addEventListener('timeupdate', () => {
...
}
...a dozen other addEventListeners for different elements fetched by querySelectors...
return { playPause, toggleFullScreen, fullscreen }
}
export default useVideoPlayer;
我正在将 playPause
、toggleFullscreen
函数和 fullscreen
reactcontext 从 useVideoPlayer
挂钩传回反应容器。
我使用 &&
并检查 fullscreen
是真还是假以呈现 <VideoPlayer/>
或不
当组件不在 DOM 中时,useVideoPlayer
挂钩不起作用,我该如何解决?
Uncaught TypeError: Cannot read property 'querySelector' of null
at eval (useVideoPlayer.js:41)
at commitHookEffectListMount (react-dom.development.js:19731)
at commitPassiveHookEffects (react-dom.development.js:19769)
at HTMLUnknownElement.callCallback (react-dom.development.js:188)
at Object.invokeGuardedCallbackDev (react-dom.development.js:237)
at invokeGuardedCallback (react-dom.development.js:292)
at flushPassiveEffectsImpl (react-dom.development.js:22853)
at unstable_runWithPriority (scheduler.development.js:653)
at runWithPriority (react-dom.development.js:11039)
at flushPassiveEffects (react-dom.development.js:22820)
我试过 useLayoutEffect
,通过 useRef(null)
并包装在 if (containerRef.current) {}
中,但没有区别
您需要在尝试使用之前检查该元素是否存在:
const pauseButton = playPauseButton && playPauseButton.querySelector('.paused');
如果您想要更具可扩展性的东西,您可以在 VideoContainer
中显式控制它是否呈现,然后将其传递给您的挂钩:
const VideoContainer = ({ info }) => {
const [mounted, setMounted] = useState(false)
const { playPause, toggleFullScreen, fullscreen } = useVideoPlayer(mounted)
return (
...
{mounted ? <VideoPlayer/> : null}