【问题标题】:converting prevstates in class component to funcitonal component?将类组件中的 prevstate 转换为功能组件?
【发布时间】:2021-09-13 08:00:20
【问题描述】:

prevstate 转换为使用回调的功能挂钩。我不确定如何将其转换为 prevstate 的功能组件

我在链接中的功能组件:--

https://codesandbox.io/live/407f82cc05a

我的班级组件在下面。 有人可以说我在做什么是错的吗?渲染时遇到错误..

import React, {Component} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  TextInput,
  StatusBar,
  TouchableOpacity,
  Dimensions,
  Image,
  Modal,
} from 'react-native';

import {
  RTCPeerConnection,
  RTCIceCandidate,
  RTCSessionDescription,
  RTCView,
  MediaStream,
  MediaStreamTrack,
  mediaDevices,
  registerGlobals,
} from 'react-native-webrtc';





import io from 'socket.io-client';

const dimensions = Dimensions.get('window');

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      localStream: null, // used to hold local stream object to avoid recreating the stream everytime a new offer comes
      remoteStream: null, // used to hold remote stream object that is displayed in the main screen

      remoteStreams: [], // holds all Video Streams (all remote streams)
      peerConnections: {}, // holds all Peer Connections
      selectedVideo: null,

      status: 'Please wait...',

      pc_config: {
        iceServers: [
          {
            url: 'stun:stun.l.google.com:19302',
          },
        ],
      },

      sdpConstraints: {
        mandatory: {
          OfferToReceiveAudio: true,
          OfferToReceiveVideo: true,
        },
      },

      messages: [],
      sendChannels: [],
      disconnected: false,
      room: null,
      connect: false,
      camera: true,
      mic: true,
      showmodal: false,
    };

    this.serviceIP = 'https://328b-171-76-106-111.ngrok.io/webrtcPeer';

    // this.sdp
    this.socket = null;
    // this.candidates = []
  }

  getLocalStream = () => {
    const success = stream => {
      console.log('localStream... ', stream.toURL());
      this.setState({
        localStream: stream,
      });

      this.whoisOnline();
    };

    const failure = e => {
      console.log('getUserMedia Error: ', e);
    };

    let isFront = true;
    mediaDevices.enumerateDevices().then(sourceInfos => {
      console.log(sourceInfos);
      let videoSourceId;
      for (let i = 0; i < sourceInfos.length; i++) {
        const sourceInfo = sourceInfos[i];
        if (
          sourceInfo.kind == 'videoinput' &&
          sourceInfo.facing == (isFront ? 'front' : 'environment')
        ) {
          videoSourceId = sourceInfo.deviceId;
        }
      }

      const constraints = {
        audio: true,
        video: {
          mandatory: {
            minWidth: 500, // Provide your own width, height and frame rate here
            minHeight: 300,
            minFrameRate: 30,
          },
          facingMode: isFront ? 'user' : 'environment',
          optional: videoSourceId ? [{sourceId: videoSourceId}] : [],
        },
      };

      mediaDevices.getUserMedia(constraints).then(success).catch(failure);
    });
  };

  whoisOnline = () => {
    // let all peers know I am joining
    console.log('-----------whoisOnline-------------');
    console.log('this.socket.id----', this.socket.id);

    this.sendToPeer('onlinePeers', null, {local: this.socket.id});
  };

  sendToPeer = (messageType, payload, socketID) => {
    console.log('-----------sendToPeer------------');
    console.log('messageType ', messageType);
    console.log(' payload ', payload);
    console.log('socketID ', socketID);
    this.socket.emit(messageType, {
      socketID,
      payload,
    });
  };

  createPeerConnection = (socketID, callback) => {
  
    try {
      let pc = new RTCPeerConnection(this.state.pc_config);

      // add pc to peerConnections object
      const peerConnections = {...this.state.peerConnections, [socketID]: pc};

      

      this.setState({
        peerConnections: peerConnections,
      });
    
      pc.onicecandidate = e => {
        console.log('--------- pc.onicecandidate-----------');
        if (e.candidate) {
          console.log('e.candidate ---- ', e.candidate);
          this.sendToPeer('candidate', e.candidate, {
            local: this.socket.id,
            remote: socketID,
          });
        }
      };

      pc.oniceconnectionstatechange = e => {
        // if (pc.iceConnectionState === 'disconnected') {
        //   const remoteStreams = this.state.remoteStreams.filter(stream => stream.id !== socketID)
        //   this.setState({
        //     remoteStream: remoteStreams.length > 0 && remoteStreams[0].stream || null,
        //   })
        // }
      };

      pc.onaddstream = e => {
      
        debugger;

        let _remoteStream = null;
        let remoteStreams = this.state.remoteStreams;
        let remoteVideo = {};

      ;

        // 1. check if stream already exists in remoteStreams
        // const rVideos = this.state.remoteStreams.filter(stream => stream.id === socketID)

        remoteVideo = {
          id: socketID,
          name: socketID,
          stream: e.stream,
        };

        

        remoteStreams = [...this.state.remoteStreams, remoteVideo];

      

        this.setState(prevState => {
          // If we already have a stream in display let it stay the same, otherwise use the latest stream

          const remoteStream =
            prevState.remoteStreams.length > 0 ? {} : {remoteStream: e.stream};

          

          // get currently selected video
          let selectedVideo = prevState.remoteStreams.filter(
            stream => stream.id === prevState.selectedVideo.id,
          );

          

          // if the video is still in the list, then do nothing, otherwise set to new video stream
          selectedVideo = selectedVideo.length
            ? {}
            : {selectedVideo: remoteVideo};


          return {
            // selectedVideo: remoteVideo,
            ...selectedVideo,
            // remoteStream: e.streams[0],
            ...remoteStream,
            remoteStreams: remoteStreams, //: [...prevState.remoteStreams, remoteVideo]
          };
        });
        



      pc.close = () => {
        
      };

      if (this.state.localStream) {
        pc.addStream(this.state.localStream);
      }

      callback(pc);
    } catch (e) {
      console.log('Something went wrong! pc not created!!', e);

      callback(null);
    }
  };

  componentDidMount = () => {};

  joinRoom = () => {
    this.setState({
      connect: true,
    });

    const room = this.state.room || '';

    this.socket = io.connect(this.serviceIP, {
      path: '/io/webrtc',
      query: {
        room: `/${room}`,
      },
    });

    this.socket.on('connection-success', data => {
      
      this.getLocalStream();

      const status =
        data.peerCount > 1
          ? `Total Connected Peers to room ${this.state.room}: ${data.peerCount}`
          : this.state.status;
      
      this.setState({
        status: status,
        messages: data.messages,
      });
    });

    this.socket.on('joined-peers', data => {
    
      this.setState({
        status:
          data.peerCount > 1
            ? `Total Connected Peers to room ${this.state.room}: ${data.peerCount}`
            : 'Waiting for other peers to connect',
      });
    });

    this.socket.on('peer-disconnected', data => {
      

      

      const remoteStreams = this.state.remoteStreams.filter(
        stream => stream.id !== data.socketID,
      );

      

      this.setState(prevState => {
        // check if disconnected peer is the selected video and if there still connected peers, then select the first
        

        const selectedVideo =
          prevState.selectedVideo.id === data.socketID && remoteStreams.length
            ? {selectedVideo: remoteStreams[0]}
            : null;
        
        
        return {
          remoteStreams,
          ...selectedVideo,
          status:
            data.peerCount > 1
              ? `Total Connected Peers to room ${this.state.room}: ${data.peerCount}`
              : 'Waiting for other peers to connect',
        };
      });
      
    });

    this.socket.on('online-peer', socketID => {
      debugger;
  

    
      this.createPeerConnection(socketID, pc => {
  
        if (pc) {
        
          const handleSendChannelStatusChange = event => {
            console.log(
              'send channel status: ' + this.state.sendChannels[0].readyState,
            );
          };

          const sendChannel = pc.createDataChannel('sendChannel');
          sendChannel.onopen = handleSendChannelStatusChange;
          sendChannel.onclose = handleSendChannelStatusChange;

    

          

          this.setState(prevState => {
            
            

            return {
              sendChannels: [...prevState.sendChannels, sendChannel],
            };
          });
          

          // Receive Channels
          const handleReceiveMessage = event => {
            

            const message = JSON.parse(event.data);
          
            this.setState(prevState => {

              return {
                messages: [...prevState.messages, message],
              };
            });
            
          };

          const handleReceiveChannelStatusChange = event => {
            
            if (this.receiveChannel) {
              console.log(
                "receive channel's status has changed to " +
                  this.receiveChannel.readyState,
              );
            }
          };

          const receiveChannelCallback = event => {
        
            const receiveChannel = event.channel;
            receiveChannel.onmessage = handleReceiveMessage;
            receiveChannel.onopen = handleReceiveChannelStatusChange;
            receiveChannel.onclose = handleReceiveChannelStatusChange;
          };

          pc.ondatachannel = receiveChannelCallback;

          pc.createOffer(this.state.sdpConstraints).then(sdp => {
            pc.setLocalDescription(sdp);

            this.sendToPeer('offer', sdp, {
              local: this.socket.id,
              remote: socketID,
            });
          });
        }
      });
    });

    this.socket.on('offer', data => {
  
    
      this.createPeerConnection(data.socketID, pc => {

        pc.addStream(this.state.localStream);

        // Send Channel
        const handleSendChannelStatusChange = event => {
          
          console.log(
            'send channel status: ' + this.state.sendChannels[0].readyState,
          );
        };

        const sendChannel = pc.createDataChannel('sendChannel');
        sendChannel.onopen = handleSendChannelStatusChange;
        sendChannel.onclose = handleSendChannelStatusChange;

      


        this.setState(prevState => {
          
          return {
            sendChannels: [...prevState.sendChannels, sendChannel],
          };
        });
        
        // Receive Channels
        const handleReceiveMessage = event => {
          
          const message = JSON.parse(event.data);
          

          this.setState(prevState => {
          
            return {
              messages: [...prevState.messages, message],
            };
          });
        
        };

        const handleReceiveChannelStatusChange = event => {
          
          if (this.receiveChannel) {
            console.log(
              "receive channel's status has changed to " +
                this.receiveChannel.readyState,
            );
          }
        };

        const receiveChannelCallback = event => {
          
          
          const receiveChannel = event.channel;
          receiveChannel.onmessage = handleReceiveMessage;
          receiveChannel.onopen = handleReceiveChannelStatusChange;
          receiveChannel.onclose = handleReceiveChannelStatusChange;
        };

        pc.ondatachannel = receiveChannelCallback;
        debugger;
        pc.setRemoteDescription(new RTCSessionDescription(data.sdp)).then(
          () => {
            // 2. Create Answer
            pc.createAnswer(this.state.sdpConstraints).then(sdp => {
              pc.setLocalDescription(sdp);

              this.sendToPeer('answer', sdp, {
                local: this.socket.id,
                remote: data.socketID,
              });
            });
          },
        );
      });
    });

    this.socket.on('answer', data => {
    
      
      const pc = this.state.peerConnections[data.socketID];

      pc.setRemoteDescription(new RTCSessionDescription(data.sdp)).then(
        () => {},
      );
    });

    this.socket.on('candidate', data => {
      
      // get remote's peerConnection
      const pc = this.state.peerConnections[data.socketID];

      if (pc) pc.addIceCandidate(new RTCIceCandidate(data.candidate));
    });
      };

  switchVideo = _video => {
    debugger;
    // alert(_video)
    this.setState({
      selectedVideo: _video,
    });
  };

  stopTracks = stream => {
    stream.getTracks().forEach(function (track) {
      if (track.readyState == 'live') {
        track.stop();
      }
    });
  };

  render() {
    const {localStream, remoteStreams, peerConnections, room, connect} =
      this.state;

    const remoteVideos = remoteStreams.map(rStream => {
      return (
        <TouchableOpacity
          key={rStream.id}
          onPress={() => this.switchVideo(rStream)}>
          <View
            style={{
              flex: 1,
              width: '100%',
              backgroundColor: 'white',
              justifyContent: 'center',
              alignItems: 'center',
              padding: 2,
            }}>
            <RTCView
              key={rStream.id}
              mirror={true}
              style={{...styles.rtcViewRemote}}
              objectFit="contain"
              streamURL={rStream.stream && rStream.stream.toURL()}
              type="remote"
            />
          </View>
        </TouchableOpacity>
      );
    });

    const remoteVideo = this.state.selectedVideo ? (
      <RTCView
        key={2}
        mirror={true}
        style={{width: dimensions.width, height: dimensions.height / 3}}
        objectFit="cover"
        streamURL={
          this.state.selectedVideo && this.state.selectedVideo.stream.toURL()
        }
        type="remote"
      />
    ) : (
      <View style={{padding: 15}}>
        <Text
          style={{
            fontSize: 22,
            textAlign: 'center',
            color: 'black',
          }}>
          Waiting for Peer connection ...
        </Text>
      </View>
    );

    if (!connect)
      return (
        <SafeAreaView style={{flex: 1, backgroundColor: '#6d3434'}}>
          <StatusBar backgroundColor="#ffff" barStyle={'dark-content'} />
          <Image source={require('./logo.png')} />
          <View
            style={{
              ...styles.buttonsContainer,
              // backgroundColor: 'teal',
              paddingHorizontal: 15,
            }}>
            <TextInput
              // editable
              maxLength={10}
              slectionColor={'green'}
              placeholderTextColor="lightgrey"
              placeholder="e.g. room1"
              style={{
                width: 200,
                color: 'black',
                fontSize: 18,
                backgroundColor: 'white',
                borderColor: '#000000',
                borderWidth: 1,
                paddingHorizontal: 10,
              }}
              value={room}
              onChangeText={text => this.setState({room: text})}
            />

            <Button transparent onPress={this.joinRoom}>
              <Icon
                name="arrow-right-circle"
                type="Feather"
                style={{fontSize: 30, color: 'blue'}}
              />
            </Button>
          </View>
        </SafeAreaView>
      );

    return (
      <SafeAreaView style={{flex: 1, backgroundColor: '#6d3434'}}>
        <StatusBar backgroundColor="#ffff" barStyle={'dark-content'} />

        <View
          style={{
            ...styles.buttonsContainer,
            justifyContent: 'center',
            alignItems: 'center',
            paddingHorizontal: 15,
          }}>
          <Button
            transparent
            onPress={() => {
              this.setState({
                showmodal: !this.state.showmodal,
              });
            }}>
            <Icon
              name="user-plus"
              type="Feather"
              style={{
                fontSize: 30,
                color: `orange`,
              }}
            />
          </Button>
          <Button
            transparent
            onPress={() => {
              debugger;
              const videoTrack = localStream
                .getTracks()
                .filter(track => track.kind === 'video');
              videoTrack[0].enabled = !videoTrack[0].enabled;
              this.setState({
                camera: videoTrack[0].enabled,
              });
            }}>
            <Icon
              name="video-off"
              type="Feather"
              style={{
                fontSize: 30,
                color: `${(this.state.camera && 'green') || 'red'}`,
              }}
            />
          </Button>

          <Button
            transparent
            onPress={() => {
              debugger;
              const audioTrack = localStream
                .getTracks()
                .filter(track => track.kind === 'audio');
              audioTrack[0].enabled = !audioTrack[0].enabled;
              this.setState({
                mic: audioTrack[0].enabled,
              });
            }}>
            <Icon
              name="mic"
              style={{
                fontSize: 30,
                color: `${(this.state.mic && 'green') || 'red'}`,
              }}
            />
          </Button>

          <Button
            transparent
            onPress={() => {
              // disconnect socket
              this.socket.close();

              // localStream.stop()
              this.stopTracks(localStream);

              // stop all remote audio & video tracks
              remoteStreams.forEach(rVideo => this.stopTracks(rVideo.stream));

              // stop all remote peerconnections
              peerConnections &&
                Object.values(peerConnections).forEach(pc => pc.close());

              this.setState({
                connect: false,
                peerConnections: {},
                remoteStreams: [],
                localStream: null,
                remoteStream: null,
                selectedVideo: null,
              });
            }}>
            <Icon name="close" style={{fontSize: 30, color: 'gray'}} />
          </Button>
        </View>
        <Modal
          animationType={'slide'}
          transparent={true}
          visible={this.state.showmodal}
          onRequestClose={() => {
            console.log('Modal has been closed.');
          }}>
          <View style={styles.modal}>
            <Button
              transparent
              onPress={() => {
                this.setState({
                  showmodal: !this.state.showmodal,
                });
              }}>
              <Icon name="close" style={{fontSize: 30, color: '#05375a'}} />
            </Button>
            <View style={styles.container}>
              <TouchableOpacity style={styles.button}>
                <Text>chat</Text>
              </TouchableOpacity>
              <TouchableOpacity style={styles.button}>
                <Text>screen share </Text>
              </TouchableOpacity>
            </View>
          </View>
        </Modal>
        <View style={{...styles.videosContainer}}>
          <View
            style={{
              position: 'absolute',
              zIndex: 1,
              top: 10,
              right: 10,
              width: 100,
              backgroundColor: 'black',
            }}>
            <View style={{flex: 1}}>
              <TouchableOpacity
                onPress={() => localStream._tracks[1]._switchCamera()}>
                <View>
                  <RTCView
                    key={1}
                    zOrder={0}
                    objectFit="cover"
                    style={{...styles.rtcView}}
                    streamURL={localStream && localStream.toURL()}
                    type="local"
                  />
                </View>
              </TouchableOpacity>
            </View>
          </View>
          <View
            style={{
              flex: 1,
              width: '100%',
              backgroundColor: '#6495ed',
              justifyContent: 'center',
              alignItems: 'center',
            }}>
            {remoteVideo}
          </View>

          <ScrollView horizontal={true} style={{...styles.scrollView}}>
            {remoteVideos}
          </ScrollView>
        </View>
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttonsContainer: {
    flexDirection: 'row',
    backgroundColor: 'white',
  },
  button: {
    margin: 5,
    paddingVertical: 10,
    backgroundColor: 'lightgrey',
    borderRadius: 5,
  },
  textContent: {
    fontFamily: 'Avenir',
    fontSize: 20,
    textAlign: 'center',
  },
  videosContainer: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
  },
  rtcView: {
    width: 100, //dimensions.width,
    height: 150, //dimensions.height / 2,
    backgroundColor: 'black',
    borderRadius: 5,
  },
  scrollView: {
    // flex: 1,
    // // flexDirection: 'row',
    // backgroundColor: 'black',
    // padding: 15,
    position: 'absolute',
    zIndex: 0,
    bottom: 10,
    right: 0,
    left: 0,
    // width: 100, height: 200,
    backgroundColor: 'rgba(0, 0, 0, 0.3)',
  },
  rtcViewRemote: {
    width: 110, //dimensions.width,
    height: 110, //dimensions.height / 2,
    // backgroundColor: 'black',
    borderRadius: 5,
  },
  modal: {
    height: '100%',
    marginTop: 'auto',
    backgroundColor: 'white',
  },
});

export default App;

【问题讨论】:

  • idk 这看起来不像是我的回调

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


【解决方案1】:

它看起来不像 setState 回调,

我会尝试遵循您的代码和变量,因为我不知道您要做什么

const [state,setstate] = useState({
remoteStreams:[],
selectedVideo:{},
remoteStream:{}
});

setstate((prevstate)=>{
const {remoteStreams,selectedVideo} = prevstate;
const remoteStream = remoteStreams.length > 0 ? {} : e.stream;
let newSelectedVideo = remoteStreams.filter(
        stream => stream.id === selectedVideo.id,
 );

return {
    ...prevstate,
    selectedVideo: newSelectedVideo.length > 0 ? {} : remoteVideo,
    remoteStream
   }
}

对不起,如果我错了,但你明白了。

顺便说一句,这就是 setState 回调的样子

类组件

this.setState({
loading:false
},()=>{
   console.log('loading finished');
})

挂钩

useEffect(()=>{
if(!loading){
 console.log('loading finished')
}
},[state.loading])

setState({
  ...state,
  loading:false
})

【讨论】:

    猜你喜欢
    • 2020-02-08
    • 2020-08-26
    • 1970-01-01
    • 2020-06-22
    • 2021-05-29
    • 2022-01-08
    相关资源
    最近更新 更多