You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过React Context实现音乐播放器组件间currentSong数据传递?

用React Context实现歌曲状态共享的完整方案

步骤1:创建PlayerContext

首先需要创建一个Context对象,作为状态传递的载体:

const PlayerContext = React.createContext();

步骤2:完善PlayerProvider组件

将歌曲选中状态的管理从Songs组件移到PlayerProvider中,让它成为所有子组件的共享状态,同时提供修改状态的方法:

const PlayerProvider = ({ children }) => {
  const [currentSong, setCurrSongSel] = React.useState('');
  
  // 把状态和修改方法存入context值
  const contextValue = {
    currentSong,
    setCurrSongSel
  };

  return (
    <PlayerContext.Provider value={contextValue}>
      {children}
    </PlayerContext.Provider>
  );
};

步骤3:实现usePlayerContext自定义Hook

封装useContext调用逻辑,简化组件获取Context的过程,同时添加校验确保组件在Provider内部使用:

const usePlayerContext = () => {
  const context = React.useContext(PlayerContext);
  if (!context) {
    throw new Error('usePlayerContext must be used within a PlayerProvider');
  }
  return context;
};

步骤4:修改Songs组件

移除自身的useState,通过自定义Hook获取Context中的状态和修改方法,点击歌曲时更新选中状态:

const Songs = () => {
  const { currentSong, setCurrSongSel } = usePlayerContext();

  return (
    <PlayList>
      {songList.map(({ title, author, id }) => (
        <Song key={id} onClick={()=> setCurrSongSel(id)}>
          <SongTitle data-testid={id} active={currentSong === id}>
            {title}
          </SongTitle>
          <p>{author}</p>
        </Song>
      ))}
    </PlayList>
  );
};

步骤5:修改ControlBar组件

通过自定义Hook获取当前选中的歌曲ID,匹配对应的歌曲信息并显示:

const ControlBar = () => {
  const { currentSong } = usePlayerContext();
  // 根据选中ID匹配歌曲,默认显示提示文本
  const selectedSong = songList.find(song => song.id === currentSong) || {};
  const title = selectedSong.title ? `${selectedSong.title} - ${selectedSong.author}` : '未选择歌曲';

  return (
    <BottomBar>
      <BarSongTitle data-testid="barTitle">{title}</BarSongTitle>
      <div>
        <Button data-testid="previousButton">Previous</Button>
        <Button data-testid="nextButton">Next</Button>
        <Button data-testid="currentModeButton">{buttonLabels[0]}</Button>
      </div>
    </BottomBar>
  );
};

完整修改后的代码

import React from 'react';
import {
  BarSongTitle,
  BottomBar,
  Button,
  PlayList,
  Song,
  SongTitle,
} from './styles.js';
import { songList } from './constants.js';

const buttonLabels = ['Not replaying', 'Replaying all', 'Replaying one'];

// 创建PlayerContext
const PlayerContext = React.createContext();

// 完善PlayerProvider,管理共享状态
const PlayerProvider = ({ children }) => {
  const [currentSong, setCurrSongSel] = React.useState('');
  
  const contextValue = {
    currentSong,
    setCurrSongSel
  };

  return (
    <PlayerContext.Provider value={contextValue}>
      {children}
    </PlayerContext.Provider>
  );
};

// 自定义Hook简化Context访问
const usePlayerContext = () => {
  const context = React.useContext(PlayerContext);
  if (!context) {
    throw new Error('usePlayerContext must be used within a PlayerProvider');
  }
  return context;
};

// 修改ControlBar获取共享状态
const ControlBar = () => {
  const { currentSong } = usePlayerContext();
  const selectedSong = songList.find(song => song.id === currentSong) || {};
  const title = selectedSong.title ? `${selectedSong.title} - ${selectedSong.author}` : '未选择歌曲';

  return (
    <BottomBar>
      <BarSongTitle data-testid="barTitle">{title}</BarSongTitle>
      <div>
        <Button data-testid="previousButton">Previous</Button>
        <Button data-testid="nextButton">Next</Button>
        <Button data-testid="currentModeButton">{buttonLabels[0]}</Button>
      </div>
    </BottomBar>
  );
};

// 修改Songs使用Context的状态和方法
const Songs = () => {
  const { currentSong, setCurrSongSel } = usePlayerContext();

  return (
    <PlayList>
      {songList.map(({ title, author, id }) => (
        <Song key={id} onClick={()=> setCurrSongSel(id)}>
          <SongTitle data-testid={id} active={currentSong === id}>
            {title}
          </SongTitle>
          <p>{author}</p>
        </Song>
      ))}
    </PlayList>
  );
};

export { PlayerProvider, Songs, ControlBar };

核心逻辑说明

  • 状态提升:将原本Songs组件内的选中状态移到PlayerProvider中,让它成为所有子组件的共享状态。
  • Context传递:通过PlayerContext.Provider把状态和修改方法传递给所有嵌套子组件。
  • 自定义Hook:封装Context获取逻辑,同时添加错误校验,避免组件在Provider外部使用时出现异常。

内容的提问来源于stack exchange,提问作者UI_Dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 14:32:06