React中跨JSX文件实现点击按钮控制音乐播放器显隐
实现导航栏按钮控制跨组件音乐播放器显示隐藏的方案
因为Header和MusicPlayer属于不同组件,我们可以通过状态提升的方式,将控制播放器显示的状态放到它们的共同父组件中,再通过props传递状态和回调函数来实现交互。
步骤1:修改共同父组件(如App.js)
将播放器的显示状态维护在父组件中,同时定义切换状态的回调函数,分别传递给两个子组件:
import React, { useState } from 'react'; import Header from './Header'; import MusicPlayer from './MusicPlayer'; function App() { // 控制播放器显示/隐藏的状态,默认显示 const [showPlayer, setShowPlayer] = useState(true); // 切换播放器显示状态的回调函数 const togglePlayerVisibility = () => { setShowPlayer(prevState => !prevState); }; return ( <div className="App"> {/* 将切换回调传给Header */} <Header onToggleMusic={togglePlayerVisibility} /> {/* 将显示状态传给MusicPlayer */} <MusicPlayer show={showPlayer} /> {/* 其他页面组件 */} </div> ); } export default App;
步骤2:修改Header组件
移除组件内部的viewMusic状态,接收父组件传递的回调函数,点击音乐按钮时调用该回调:
import React from 'react' import SunIcon from './Icons/SunIcon' import MoonIcon from './Icons/MoonIcon' import avatar from '../assets/avatar.jpeg' import '../css/skeleton.css' import '../css/normalize.css' import '../css/components.css' import { ThemeType } from '../ts/types'; import { BiMusic } from 'react-icons/bi' // 接收父组件传递的onToggleMusic回调 function Header({ onToggleMusic }): JSX.Element { const dataTheme = document.body.getAttribute('data-theme'); const [theme, setTheme] = React.useState<ThemeType>((): ThemeType => dataTheme === "light" ? "light" : 'dark'); React.useEffect(() => { document.body.setAttribute('data-theme', theme) }, [theme]); const handleSwitchTheme = () => { setTheme(isDark ? 'light' : 'dark') } const isDark = theme === 'dark' return ( <div className="Header container"> <div className="ten columns Header__inner"> <img src={avatar} alt="avatar" /> <h2> <b>Sagnik. </b> </h2> </div> {/* 点击按钮时调用父组件的切换回调 */} <button className='music-btn' onClick={onToggleMusic}> <BiMusic fontSize="2.5rem"/> </button> <button className="switch-theme-button" onClick={handleSwitchTheme}> {isDark ? <SunIcon color="white" /> : <MoonIcon />} </button> </div> ) } export default Header
步骤3:修改MusicPlayer组件
移除组件内部的view状态,改用父组件传递的show属性控制渲染,同时新增逻辑:当播放器隐藏时自动暂停音乐,提升用户体验:
import React, {useState, useEffect} from 'react' import { BiSkipPrevious, BiSkipNext, BiPause, BiPlay } from 'react-icons/bi'; import { songs } from '../assets/items'; // 接收父组件传递的show属性 export default function MusicPlayer({ show }) { const [isPlaying, setIsPlaying] = useState(true) const [isPlayAnime, setIsPlayAnime] = useState(false) const totalSongs = songs.length let songIdx = 0 const [song, setSong] = useState({info: songs[songIdx], audioSrc: new Audio(songs[songIdx].audio)}) // 当播放器隐藏时自动暂停音乐 useEffect(() => { if (!show) { pauseSong(); } }, [show]); const prevSong = () => { if(songIdx < 0) { songIdx = 0 } else { songIdx = songIdx - 1 } setSong({info: songs[songIdx], audioSrc: new Audio(songs[songIdx].audio)}) } const nextSong = () => { if(songIdx > totalSongs - 1) { songIdx = 0 } else { songIdx = songIdx + 1 } setSong({info: songs[songIdx], audioSrc: new Audio(songs[songIdx].audio)}) } const playSong = () => { setIsPlaying(false) setIsPlayAnime(!isPlayAnime); song.audioSrc.play() } const pauseSong = () => { setIsPlaying(true) setIsPlayAnime(!isPlayAnime); song.audioSrc.pause() } return ( <div> {/* 根据父组件传递的show属性控制渲染 */} {show && (<div className={`music-container ${isPlayAnime ? `play` : ""}`}> <div className='music-wrapper'> <div className='music-info'> <h4 id='title'>{song.info.title}</h4> </div> <div className='img-container'> <img src={song.info.image} alt='music-cover' id='cover'/> </div> <div className='navigation'> <button id="prev" className='btn-prev action-btn' onClick={prevSong}> <BiSkipPrevious fontSize='3rem' /> </button> {isPlaying === true ? (<button id="play" className='btn-play action-btn-big' onClick={playSong}> <BiPlay fontSize='4rem' /> </button>) : <button id="pause" className='btn-play action-btn-big' onClick={pauseSong}> <BiPause fontSize='4rem' /> </button> } <button id="next" className='btn-next action-btn' onClick={nextSong} > <BiSkipNext fontSize='3rem' /> </button> </div> </div> </div>)} </div> ) }
原理说明
通过将共享状态提升到共同父组件,实现了跨组件的状态同步:Header负责触发状态变更,MusicPlayer根据状态变化调整自身的显示状态,这种方式是React中处理跨组件状态交互最直接、轻量的方案。
内容的提问来源于stack exchange,提问作者Roopesh Saravanan
相关产品推荐
相关产品推荐

