【问题标题】:How to pass react-native props from functional component to class component如何将 react-native 道具从功能组件传递到类组件
【发布时间】:2021-07-18 01:20:11
【问题描述】:

我正在为流媒体应用程序创建一个音乐播放器,并且我想制作一个动态播放列表。我正在使用 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",
  },
});

【问题讨论】:

    标签: javascript reactjs react-native react-props react-component


    【解决方案1】:

    您几乎拥有它,您只是错过了类和功能组件之间的一个概念差异。即组件内部如何使用 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(又名组件/类实例),但它可能并不总是相同的? 请参阅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 支持类查找。

    【讨论】:

    • 非常感谢!它完美地工作,我是使用 React-native 的新手,我很高兴学习这个。你是摇滚明星,再次感谢你!
    猜你喜欢
    • 2020-09-11
    • 2017-02-19
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 2021-01-30
    • 2021-02-02
    • 1970-01-01
    相关资源
    最近更新 更多