【发布时间】: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