next.js react-youtube TypeError:无法读取null的属性(阅读“playVideo”)

qojgxg4l  于 2023-04-05  发布在  React
关注(0)|答案(1)|浏览(161)

bounty将在2天后过期。回答此问题可获得+100声望奖励。Anonymous希望引起更多人关注此问题。

未处理的运行时错误TypeError:无法读取null的属性(阅读“playVideo”)
调用堆栈eval node_modules/react-youtube/node_modules/youtube-player/dist/index.js(65:0)new Promise
exports.default node_modules/react-youtube/node_modules/youtube-player/dist/index.js(64:0)createPlayer node_modules/react-youtube/dist/YouTube.esm.js(170:41)
https://upload.cc/i1/2023/02/26/daWAmu.png
这个错误可能发生在我点击分页来获取视频或只是加载页面时,我在页面上显示三个视频,当想要获取更多时更改页面。对不起,英语不是我的母语。
React 18.2.0 Next 13.1.6 react-youtube 10.1.0

const Playlist = ({ playlistId }) => {
  const [videos, setVideos] = useState([]);
  const [currentPage, setCurrentPage] = useState(0);
  const isMobile = useMediaQuery({ maxWidth: 640 });
  const isPad = useMediaQuery({ maxWidth: 1180 });
  const videosPerPage = isMobile ? 1 : isPad ? 2 : 3;

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(
          `https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=${playlistId}&key=${process.env.NEXT_PUBLIC_ytAPI}`
        );
        const data = await response.json();
        setVideos(data.items);
        console.log('data: ', data);
      } catch (error) {
        console.log(error);
      }
    };
    fetchData();
  }, [playlistId]);

  const handlePageClick = ({ selected }) => {
    setCurrentPage(selected);
  };

  const currentVideos = useMemo(() => {
    const offset = currentPage * videosPerPage;
    return videos.slice(offset, offset + videosPerPage);
  }, [currentPage, videos, videosPerPage]);

  const getOpts = useCallback(() => {
    return {
      playerVars: {
        autoplay: 0,
      },
    };
  }, []);

  const opts = getOpts();

  return (
    <>
      <div className='flex container justify-center my-10'>
        {currentVideos.map((video) => (
          <div
            key={video.id}
            className='w-full'
          >
            <YouTubePlayer
              className='video-container'
              videoId={video.snippet.resourceId.videoId}
              opts={opts}
            />
            <h2 className='text-center m-4'>{video.snippet.title}</h2>
          </div>
        ))}
      </div>
      <ReactPaginate
        className='item flex w-full justify-center mb-8'
        previousLabel={'« prev'}
        nextLabel={'next »'}
        breakLabel={'...'}
        marginPagesDisplayed={0}
        activeClassName={'active'}
        breakClassName={'disabled'}
        containerClassName={'pagination'}
        pageCount={Math.ceil(videos.length / videosPerPage)}
        onPageChange={handlePageClick}
        forcePage={currentPage}
        pageRangeDisplayed={3}
      />
    </>
  );
};

export default Playlist;

我尝试用react-player替换react-youtube,但得到了相同的错误消息,所以我认为这可能不是由npm包引起的

oalqel3c

oalqel3c1#

您可能需要等待API的fetch请求。您可以像这样重新构造代码:

const Playlist = ({ playlistId }) => {
  const [videos, setVideos] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  // ...

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(
          `https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=${playlistId}&key=${process.env.NEXT_PUBLIC_ytAPI}`
        );
        const data = await response.json();
        setVideos(data.items);
        setIsLoading(false); // set isLoading to false after data is fetched
      } catch (error) {
        console.log(error);
        setIsLoading(false); // also set isLoading to false on error
      }
    };
    fetchData();
  }, [playlistId]);

  // ...

  return (
    <>
      {isLoading ? (
        <div>Loading...</div>
      ) : (
        <div className='flex container justify-center my-10'>
          {currentVideos.map((video) => (
            <div key={video.id} className='w-full'>
              <YouTubePlayer
                className='video-container'
                videoId={video.snippet.resourceId.videoId}
                opts={opts}
              />
              <h2 className='text-center m-4'>{video.snippet.title}</h2>
            </div>
          ))}
        </div>
      )}
      {/* ... */}
    </>
  );
};

现在它显示Loading...,直到您从API获得响应。

相关问题