我正在为流媒体应用创建音乐播放器,并且想要制作动态播放列表。我正在使用 Expo AV 和 Firebase 来存储音乐和信息。
我已经配置了所有东西,但我无法将“cancionesPlaylist”道具(它已经是一个数组)从父功能组件传递到子类组件。这是我的代码:
import { StyleSheet, TouchableOpacity, View, Image } from "react-native";
import { Title, Text } from "react-native-paper";
import { LinearGradient } from "expo-linear-gradient";
import { Button } from "../components/Button";
import { Audio, Video } from "expo-av";
import firebase from "../utils/firebase";
import "firebase/firestore";
import { Ionicons } from "@expo/vector-icons";
export default function ReproductorAudio(props) {
const { route } = props;
const { canciones } = route.params;
const cancionesPlaylist = canciones;
return <ReproductorMusica cancionesPlaylist={cancionesPlaylist} />;
}
class ReproductorMusica extends React.Component {
constructor(props) {
super(props);
const cancionesPlaylist = props.cancionesPlaylist;
console.log(cancionesPlaylist);
}
state = {
isPlaying: false,
playbackInstance: null,
currentIndex: 0,
volume: 1.0,
isBuffering: false,
};
async componentDidMount() {
try {
await Audio.setAudioModeAsync({
allowsRecordingIOS: false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,
shouldDuckAndroid: true,
staysActiveInBackground: true,
playThroughEarpieceAndroid: true,
});
this.loadAudio();
} catch (e) {
console.log(e);
}
}
async loadAudio() {
const { currentIndex, isPlaying, volume } = this.state;
try {
const playbackInstance = new Audio.Sound();
const source = {
uri: cancionesPlaylist[currentIndex].uri,
};
const status = {
shouldPlay: isPlaying,
volume,
};
playbackInstance.setOnPlaybackStatusUpdate(this.onPlaybackStatusUpdate);
await playbackInstance.loadAsync(source, status, false);
this.setState({ playbackInstance });
} catch (e) {
console.log(e);
}
}
onPlaybackStatusUpdate = (status) => {
this.setState({
isBuffering: status.isBuffering,
});
};
handlePlayPause = async () => {
const { isPlaying, playbackInstance } = this.state;
isPlaying
? await playbackInstance.pauseAsync()
: await playbackInstance.playAsync();
this.setState({
isPlaying: !isPlaying,
});
};
handlePreviousTrack = async () => {
let { playbackInstance, currentIndex } = this.state;
if (playbackInstance) {
await playbackInstance.unloadAsync();
currentIndex < cancionesPlaylist.length - 1
? (currentIndex -= 1)
: (currentIndex = 0);
this.setState({
currentIndex,
});
this.loadAudio();
}
};
handleNextTrack = async () => {
let { playbackInstance, currentIndex } = this.state;
if (playbackInstance) {
await playbackInstance.unloadAsync();
currentIndex < cancionesPlaylist.length - 1
? (currentIndex += 1)
: (currentIndex = 0);
this.setState({
currentIndex,
});
this.loadAudio();
}
};
renderFileInfo() {
const { playbackInstance, currentIndex } = this.state;
return playbackInstance ? (
<View style={styles.trackInfo}>
<Text style={[styles.trackInfoText, styles.largeText]}>
{cancionesPlaylist[currentIndex].name}
</Text>
<Text style={[styles.trackInfoText, styles.smallText]}>
{cancionesPlaylist[currentIndex].author}
</Text>
<Text style={[styles.trackInfoText, styles.smallText]}>
{cancionesPlaylist[currentIndex].source}
</Text>
</View>
) : null;
}
render() {
return (
<View style={styles.container}>
<Image
style={styles.albumCover}
source={{
uri:
"http://www.archive.org/download/LibrivoxCdCoverArt8/hamlet_1104.jpg",
}}
/>
<View style={styles.controls}>
<TouchableOpacity
style={styles.control}
onPress={this.handlePreviousTrack}
>
<Ionicons name="arrow-back-circle-outline" size={48} color="#444" />
</TouchableOpacity>
<TouchableOpacity
style={styles.control}
onPress={this.handlePlayPause}
>
{this.state.isPlaying ? (
<Ionicons name="ios-pause" size={48} color="#444" />
) : (
<Ionicons name="ios-play-circle" size={48} color="#444" />
)}
</TouchableOpacity>
<TouchableOpacity
style={styles.control}
onPress={this.handleNextTrack}
>
<Ionicons
name="arrow-forward-circle-outline"
size={48}
color="#444"
/>
</TouchableOpacity>
</View>
{this.renderFileInfo()}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#aaa",
alignItems: "center",
justifyContent: "center",
},
albumCover: {
width: 250,
height: 250,
},
trackInfo: {
padding: 40,
backgroundColor: "#aaa",
},
trackInfoText: {
textAlign: "center",
flexWrap: "wrap",
color: "#550088",
},
largeText: {
fontSize: 22,
},
smallText: {
fontSize: 16,
},
control: {
margin: 20,
},
controls: {
flexDirection: "row",
},
});
答案 0 :(得分:0)
您几乎已经知道了,只是缺少类和功能组件之间的一个概念差异。即组件内部如何使用 props (docs)。
一个简单的函数式组件,就是一个函数,所有的 props 都可以在组件中任何地方访问。但是对于类组件,道具通过 this.props
绑定到类 instance。
现在查看您的代码,您正在类构造函数内部创建一个局部变量 cancionesPlaylist
,但该变量的作用域仅在构造函数 block 内。
constructor(props) {
super(props);
const cancionesPlaylist = props.cancionesPlaylist;
console.log(cancionesPlaylist);
}
因此,当您尝试在类中的任何位置访问该局部变量时,您实际上是在引用一个可能不存在(即 undefined
)的名为 cancionesPlaylist
的全局变量。您需要做的只是通过 this.props.cancionesPlaylist
访问类实例上的道具。您可以在类组件内的任何位置访问 this
(也称为组件/类实例),但它可能并不总是相同的>
总之有一点清理...
import { StyleSheet, TouchableOpacity, View, Image } from "react-native";
import { Title, Text } from "react-native-paper";
import { LinearGradient } from "expo-linear-gradient";
import { Button } from "../components/Button";
import { Audio, Video } from "expo-av";
import firebase from "../utils/firebase";
import "firebase/firestore";
import { Ionicons } from "@expo/vector-icons";
export default function ReproductorAudio(props) {
const { route } = props;
const { canciones } = route.params;
const cancionesPlaylist = canciones;
return <ReproductorMusica cancionesPlaylist={cancionesPlaylist} />;
}
class ReproductorMusica extends React.Component {
state = {
isPlaying: false,
playbackInstance: null,
currentIndex: 0,
volume: 1.0,
isBuffering: false,
};
async componentDidMount() {
try {
await Audio.setAudioModeAsync({
allowsRecordingIOS: false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,
shouldDuckAndroid: true,
staysActiveInBackground: true,
playThroughEarpieceAndroid: true,
});
this.loadAudio();
} catch (e) {
console.log(e);
}
}
async loadAudio() {
const { currentIndex, isPlaying, volume } = this.state;
try {
const playbackInstance = new Audio.Sound();
const source = {
uri: this.props.cancionesPlaylist[currentIndex].uri,
};
const status = {
shouldPlay: isPlaying,
volume,
};
playbackInstance.setOnPlaybackStatusUpdate(this.onPlaybackStatusUpdate);
await playbackInstance.loadAsync(source, status, false);
this.setState({ playbackInstance });
} catch (e) {
console.log(e);
}
}
onPlaybackStatusUpdate = (status) => {
this.setState({
isBuffering: status.isBuffering,
});
};
handlePlayPause = async () => {
const { isPlaying, playbackInstance } = this.state;
isPlaying
? await playbackInstance.pauseAsync()
: await playbackInstance.playAsync();
this.setState({
isPlaying: !isPlaying,
});
};
handlePreviousTrack = async () => {
let { playbackInstance, currentIndex } = this.state;
if (playbackInstance) {
await playbackInstance.unloadAsync();
currentIndex < this.props.cancionesPlaylist.length - 1
? (currentIndex -= 1)
: (currentIndex = 0);
this.setState({
currentIndex,
});
this.loadAudio();
}
};
handleNextTrack = async () => {
let { playbackInstance, currentIndex } = this.state;
if (playbackInstance) {
await playbackInstance.unloadAsync();
currentIndex < this.props.cancionesPlaylist.length - 1
? (currentIndex += 1)
: (currentIndex = 0);
this.setState({
currentIndex,
});
this.loadAudio();
}
};
renderFileInfo() {
const { playbackInstance, currentIndex } = this.state;
return playbackInstance ? (
<View style={styles.trackInfo}>
<Text style={[styles.trackInfoText, styles.largeText]}>
{this.props.cancionesPlaylist[currentIndex].name}
</Text>
<Text style={[styles.trackInfoText, styles.smallText]}>
{this.props.cancionesPlaylist[currentIndex].author}
</Text>
<Text style={[styles.trackInfoText, styles.smallText]}>
{this.props.cancionesPlaylist[currentIndex].source}
</Text>
</View>
) : null;
}
render() {
return (
<View style={styles.container}>
<Image
style={styles.albumCover}
source={{
uri:
"http://www.archive.org/download/LibrivoxCdCoverArt8/hamlet_1104.jpg",
}}
/>
<View style={styles.controls}>
<TouchableOpacity
style={styles.control}
onPress={this.handlePreviousTrack}
>
<Ionicons name="arrow-back-circle-outline" size={48} color="#444" />
</TouchableOpacity>
<TouchableOpacity
style={styles.control}
onPress={this.handlePlayPause}
>
{this.state.isPlaying ? (
<Ionicons name="ios-pause" size={48} color="#444" />
) : (
<Ionicons name="ios-play-circle" size={48} color="#444" />
)}
</TouchableOpacity>
<TouchableOpacity
style={styles.control}
onPress={this.handleNextTrack}
>
<Ionicons
name="arrow-forward-circle-outline"
size={48}
color="#444"
/>
</TouchableOpacity>
</View>
{this.renderFileInfo()}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#aaa",
alignItems: "center",
justifyContent: "center",
},
albumCover: {
width: 250,
height: 250,
},
trackInfo: {
padding: 40,
backgroundColor: "#aaa",
},
trackInfoText: {
textAlign: "center",
flexWrap: "wrap",
color: "#550088",
},
largeText: {
fontSize: 22,
},
smallText: {
fontSize: 16,
},
control: {
margin: 20,
},
controls: {
flexDirection: "row",
},
});
<块引用>
删除了不需要的 constructor
,并将 cancionesPlaylist
的全局变量查找更改为通过 this.props.cancionesPlaylist
对类进行 prop 查找。