【问题标题】:React music player反应音乐播放器
【发布时间】:2021-10-16 15:57:33
【问题描述】:

我想在网站上创建一个音乐播放器。想法是选择一首歌曲并自动播放。这首歌必须在所有页面上播放,我需要一个播放/暂停按钮。 我已经创建了所有组件,但我有一个错误。当我在带有播放器组件的主页上时,播放/暂停按钮无法正常工作,如果我停止音乐我无法再次启动它,它只能在其他页面上工作。这里是网站https://thebrandbar.studio/#/

App.js

import React, { useState } from 'react';
import { HashRouter as Router, Route, Switch } from "react-router-dom";
import ScrollToTop from "./helper/scrollToTop";

import Home from "./pages/Home";
import Projects from "./pages/Projects";
import Team from "./pages/Team";
import ProjectPage from "./pages/ProjectPage";
import Error from "./pages/Error";
import TermsOfUse from "./pages/TermsOfUse";
import PrivacyPolicy from "./pages/PrivacyPolicy";
import Cookies from "./pages/Cookies";


const App = () => {
    const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
    const [trackURL, setTrackURL] = useState('');
    const [playing, setPlaying] = useState(false);

    const callbackFunction = (currentTrackIndex, trackURL, playing) => {
        setCurrentTrackIndex(currentTrackIndex);
        setTrackURL(trackURL);
        setPlaying(playing);
    };

    const player = document.getElementById('player');
    const onPlayPauseClickHandler = (event) => {
        setPlaying(!playing);
        if (!playing) {
            player.play();
        } else {
            player.pause();
        }
    }
    const renderPlayBtn = () => {
        if (currentTrackIndex == null) {
            return;
        } else {
            return <div className="play-btn">
                <p onClick={onPlayPauseClickHandler} className={`play ${playing ? "red-bg" : "blue-bg"}`}>
                    {playing ? "SOUND OFF" : "SOUND ON"}
                </p>
            </div>
        }
    }

    return (
        <>
            <Router>
                <ScrollToTop />
                <Switch>
                    <Route exact path={`${process.env.PUBLIC_URL + '/'}`} >
                        <Home parentCallback={callbackFunction} player={player}/>
                    </Route>
                    <Route
                        path={`${process.env.PUBLIC_URL + '/projects'}`}
                        component={Projects}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL}/project/:projectId`}
                        component={ProjectPage}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/team'}`}
                        component={Team}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/terms'}`}
                        component={TermsOfUse}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/privacy'}`}
                        component={PrivacyPolicy}
                    />
                    <Route
                        path={`${process.env.PUBLIC_URL + '/cookies'}`}
                        component={Cookies}
                    />
                    <Route exact component={Error} />
                </Switch>
            </Router>
            <audio id="player" src={trackURL} type="audio/mpeg"></audio>
            {
                renderPlayBtn()
            }
        </>
    );
};

export default App;

主页

import React, { useState, useEffect } from 'react';
import Loader from "../container/Loader";
import { Helmet } from "react-helmet";
import Cookies from "../components/cookies";
import LayoutDefault from "../container/LayoutDefault";
import Header from "../components/header/Header";
import HeroArea from "../container/Hero";
import MusicPlayer from "../container/MusicPlayer";
import FeaturedProjects from "../container/FeaturedProjects";
import Contact from "../container/Contact";
import Footer from "../container/Footer";

const Home = ({ parentCallback, player }) => {
    const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
    const [trackURL, setTrackURL] = useState('');
    const [playing, setPlaying] = useState(false);

    const callbackFunction = (currentTrackIndex, trackURL, playing) => {
        setCurrentTrackIndex(currentTrackIndex);
        setTrackURL(trackURL);
        setPlaying(playing);
    };

    useEffect(() => {
        parentCallback(currentTrackIndex, trackURL, playing);
    });


    return (
        <Loader>
            <Helmet>
                <title>TheBrandBar</title>
            </Helmet>
            <Cookies />
            <LayoutDefault className="template-color-2 bg_color--4">
                <Header />
                <HeroArea />
                <MusicPlayer parentCallback={callbackFunction} player={player}/>
                <FeaturedProjects />
                <Contact />
                <Footer />
            </LayoutDefault>
        </Loader>
    );
};

export default Home;

和音乐播放器组件

import React, { useState, useEffect } from "react";
import { Container, Row, Col } from "react-bootstrap";

import DB from '../data/music/music.js';


const Player = ({ parentCallback }) => {

  const [tracksList] = useState(DB);
  const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
  const [trackID, setTrackID] = useState(null);
  const [trackURL, setTrackURL] = useState('');
  const [playing, setPlaying] = useState(false);

  useEffect(() => {
    parentCallback(currentTrackIndex, trackURL, playing);
  });

  const selectThisTrack = (event, trackID) => {
    let currentTrackIndex = 0;
    tracksList.map((track, index) => {
      if (track.id === trackID) {
        currentTrackIndex = index;
      }
      return track;
    });
    setCurrentTrackIndex(currentTrackIndex);
    setTrackID(tracksList[currentTrackIndex].id);
    setTrackURL(require(`../assets/player/music/${currentTrackIndex + 1}.mp3`));
    setPlaying(true);
    const player = document.getElementById('player');
    player.src = trackURL;
    player.preload = true;
    player.autoplay = true;
    player.loop = true;
    if (playing) {
      player.play();
    } else {
      player.pause();
    }
  }
  

  const renderCover = () => {
    if (!playing) {
      return <img className="img-cover-default" src={require(`../assets/player/covers/default.gif`)} alt="" />
    } else {
      return <img className="img-cover" src={require(`../assets/player/covers/${currentTrackIndex + 1}.gif`)} alt="" />
    }
  }


  return (
    <>
      <Container>
        <Row>
          <Col className="play-list" xs={{ span: 12, order: 2 }} lg={{ span: 4, order: 1 }}>
            <p className="your-rythm ">WHAT'S YOUR RYTHM?</p>
            <br />
            {DB.map((track, index) => (
              <div
                key={track.id}
                index={index}
                className={`song ${track.id === trackID ? "selected" : ""}`}
                id={track.id === trackID ? "activeTrack" : ""}
                onClick={(ev) => selectThisTrack(ev, track.id)}
              >
                <p>{track.title}</p>
              </div>
            ))}
          </Col>
          <Col xs={{ span: 12, order: 1 }} lg={{ span: 8, order: 2 }}>

            <div className="song-cover">
              {
                renderCover()
              }
            </div>

          </Col>
        </Row>
      </Container>

    </>
  );
};

export default Player;

谢谢! :)

【问题讨论】:

    标签: javascript html reactjs react-native react-hooks


    【解决方案1】:

    我认为问题出在这里:

    const player = document.getElementById('player');
        const onPlayPauseClickHandler = (event) => {
            setPlaying(!playing);
            if (!playing) {
                player.play();
            } else {
                player.pause();
            }
        }
    

    在调用 set* 之后,React 不会立即更新。相反,您必须使用useEffect 来播放/暂停。

    删除

    if (!playing) {
        player.play();
    } else {
        player.pause();
    }
    

    并在useEffect 中使用它。

    useEffect(() => {
        !playing ? player.play() : player.pause();
    }, [playing]);
    

    编辑

    useEffect 放在这里:

    const App = () => {
        const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
        const [trackURL, setTrackURL] = useState('');
        const [playing, setPlaying] = useState(false);
    
        const callbackFunction = (currentTrackIndex, trackURL, playing) => {
            setCurrentTrackIndex(currentTrackIndex);
            setTrackURL(trackURL);
            setPlaying(playing);
        };
    
        const player = document.getElementById('player');
        const onPlayPauseClickHandler = (event) => {
            setPlaying(!playing);
        }
        const renderPlayBtn = () => {
            if (currentTrackIndex == null) {
                return;
            } else {
                return <div className="play-btn">
                    <p onClick={onPlayPauseClickHandler} className={`play ${playing ? "red-bg" : "blue-bg"}`}>
                        {playing ? "SOUND OFF" : "SOUND ON"}
                    </p>
                </div>
            }
        }
    
        // PLACE IT HERE
        useEffect(() => {
            !playing ? player.play() : player.pause();
        }, [playing]);
    
        return (
            <>
                <Router>
                    <ScrollToTop />
                    <Switch>
                        <Route exact path={`${process.env.PUBLIC_URL + '/'}`} >
                            <Home parentCallback={callbackFunction} player={player}/>
                        </Route>
                        <Route
                            path={`${process.env.PUBLIC_URL + '/projects'}`}
                            component={Projects}
                        />
                        <Route
                            path={`${process.env.PUBLIC_URL}/project/:projectId`}
                            component={ProjectPage}
                        />
                        <Route
                            path={`${process.env.PUBLIC_URL + '/team'}`}
                            component={Team}
                        />
                        <Route
                            path={`${process.env.PUBLIC_URL + '/terms'}`}
                            component={TermsOfUse}
                        />
                        <Route
                            path={`${process.env.PUBLIC_URL + '/privacy'}`}
                            component={PrivacyPolicy}
                        />
                        <Route
                            path={`${process.env.PUBLIC_URL + '/cookies'}`}
                            component={Cookies}
                        />
                        <Route exact component={Error} />
                    </Switch>
                </Router>
                <audio id="player" src={trackURL} type="audio/mpeg"></audio>
                {
                    renderPlayBtn()
                }
            </>
        );
    };
    
    export default App;
    

    【讨论】:

    • 我不能在那里调用 useEffect React Hook "useEffect" is called in function "onPlayPauseClickHandler" which is neither a React function component or a custom React Hook function 并且该按钮适用于其他页面。我认为这是 app.js 和 musicPlayer 之间的冲突,但我不知道在哪里..
    • @DavidMuresan 我已经在解决方案中指出了将useEffect 放在哪里。检查一下
    • 还是不行,"Cannot read property 'play' of null"
    • @DavidMuresan 哪一行给出了这个错误?
    • 这是您在 App.js 中编辑的 !playing ? player.play() : player.pause(); 这一行。我试图在 useEffect 中关闭播放器,但它不起作用
    猜你喜欢
    • 2019-06-19
    • 1970-01-01
    • 1970-01-01
    • 2012-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-05
    • 1970-01-01
    相关资源
    最近更新 更多