我有这个视频,在zindex中播放:-1,一个按钮,一个文本输入浮动在它上面。问题是当文本发生变化时,它应该操纵该状态对象,而不是触发点击功能上的可触摸高亮。
当我使用昨天给出的建议时,错误变为警告。如果我在输入框中输入7个随机字母,我会得到7个警告说:“警告绑定()你将组件方法绑定到组件”,这意味着输入框继续调用可触摸突出显示的功能。 / p>
我正在使用这个React Native库来使用它的流媒体功能:https://github.com/oney/react-native-webrtc。这太棒了!
在其中一个例子中,https://github.com/oney/RCTWebRTCDemo/blob/master/main.js有一些我正在摆弄的代码:
_renderTextRoom() {
return (
<View style={styles.listViewContainer}>
<ListView
dataSource={this.ds.cloneWithRows(this.state.textRoomData)}
enableEmptySections={true}
renderRow={rowData =>
<Text
style={styles.whiteOut}
>{`${rowData.user}: ${rowData.message}`}</Text>}
/>
<TextInput
style={[styles.whiteOut, styles.bgWhite]}
onChangeText={value => this.setState({ textRoomValue: value })}
value={this.state.textRoomValue}
/>
<View style={styles.buttonContainer}>
<TouchableHighlight
style={styles.button}
onPress={this._textRoomPress()}>
<Text style={styles.bgWhite}>Send</Text>
</TouchableHighlight>
</View>
</View>
);
},
当我在文本字段中输入文本时,嵌套在TouchableHighlight中的this._textRoomPress()函数将被触发。什么!?当我评论它时,它不会发射。
'use strict';
import React, { Component } from 'react';
import {
Dimensions,
StyleSheet,
Text,
TouchableHighlight,
View,
TextInput,
ListView,
ScrollView
} from 'react-native';
import { userData } from '../utils/Factory';
import io from 'socket.io-client';
var socket_one = 'https://xxxxxxxxxxxxxx.herokuapp.com';
const socket = io.connect(socket_one, { transports: ['websocket'] });
import {
RTCPeerConnection,
RTCMediaStream,
RTCIceCandidate,
RTCSessionDescription,
RTCView,
MediaStreamTrack,
getUserMedia,
} from 'react-native-webrtc';
const configuration = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] };
const pcPeers = {};
let localStream;
var width = Dimensions.get('window').width; //full width
var height = Dimensions.get('window').height; //full height
function getLocalStream(isFront, callback) {
MediaStreamTrack.getSources(sourceInfos => {
console.log(sourceInfos);
let videoSourceId;
for (const i = 0; i < sourceInfos.length; i++) {
const sourceInfo = sourceInfos[i];
if (sourceInfo.kind == "video" && sourceInfo.facing == (isFront ? "front" : "back")) {
videoSourceId = sourceInfo.id;
}
}
getUserMedia({
audio: true,
video: {
mandatory: {
minWidth: 700, // Provide your own width, height and frame rate here
minHeight: 700,
minFrameRate: 30
},
facingMode: (isFront ? "user" : "environment"),
optional: [{ sourceId: sourceInfos.id }]
}
}, function(stream) {
console.log('dddd', stream);
callback(stream);
}, logError);
});
}
function join(roomID) {
socket.emit('join', roomID, function(socketIds) {
console.log('join', socketIds);
for (const i in socketIds) {
const socketId = socketIds[i];
createPC(socketId, true);
}
});
}
function createPC(socketId, isOffer) {
const pc = new RTCPeerConnection(configuration);
pcPeers[socketId] = pc;
pc.onicecandidate = function(event) {
// console.warn('onicecandidate', event.candidate);
if (event.candidate) {
socket.emit('exchange', { 'to': socketId, 'candidate': event.candidate });
}
};
function createOffer() {
pc.createOffer(function(desc) {
console.log('createOffer', desc);
pc.setLocalDescription(desc, function() {
console.log('setLocalDescription', pc.localDescription);
socket.emit('exchange', { 'to': socketId, 'sdp': pc.localDescription });
}, logError);
}, logError);
}
pc.onnegotiationneeded = function() {
console.log('onnegotiationneeded');
if (isOffer) {
createOffer();
}
}
pc.oniceconnectionstatechange = function(event) {
console.log('oniceconnectionstatechange', event.target.iceConnectionState);
if (event.target.iceConnectionState === 'completed') {
setTimeout(() => {
getStats();
}, 1000);
}
if (event.target.iceConnectionState === 'connected') {
createDataChannel();
}
};
pc.onsignalingstatechange = function(event) {
console.log('onsignalingstatechange', event.target.signalingState);
};
pc.onaddstream = function(event) {
console.log('onaddstream', event.stream);
// container.setState({ info: 'One peer join!' });
container.setState({ info: 'Connected!' });
const remoteList = container.state.remoteList;
remoteList[socketId] = event.stream.toURL();
container.setState({ remoteList: remoteList });
};
pc.onremovestream = function(event) {
console.log('onremovestream', event.stream);
};
pc.addStream(localStream);
function createDataChannel() {
if (pc.textDataChannel) {
return;
}
const dataChannel = pc.createDataChannel("text");
dataChannel.onerror = function(error) {
console.log("dataChannel.onerror", error);
};
dataChannel.onmessage = function(event) {
console.log("dataChannel.onmessage:", event.data);
container.receiveTextData({ user: socketId, message: event.data });
};
dataChannel.onopen = function() {
console.log('dataChannel.onopen');
container.setState({ textRoomConnected: true });
};
dataChannel.onclose = function() {
console.log("dataChannel.onclose");
};
pc.textDataChannel = dataChannel;
}
return pc;
}
function exchange(data) {
const fromId = data.from;
let pc;
if (fromId in pcPeers) {
pc = pcPeers[fromId];
} else {
pc = createPC(fromId, false);
}
if (data.sdp) {
console.log('exchange sdp', data);
pc.setRemoteDescription(new RTCSessionDescription(data.sdp), function() {
if (pc.remoteDescription.type == "offer")
pc.createAnswer(function(desc) {
console.log('createAnswer', desc);
pc.setLocalDescription(desc, function() {
console.log('setLocalDescription', pc.localDescription);
socket.emit('exchange', { 'to': fromId, 'sdp': pc.localDescription });
}, logError);
}, logError);
}, logError);
} else {
console.log('exchange candidate', data);
pc.addIceCandidate(new RTCIceCandidate(data.candidate));
}
}
function leave(socketId) {
console.log('leave', socketId);
const pc = pcPeers[socketId];
const viewIndex = pc.viewIndex;
pc.close();
delete pcPeers[socketId];
const remoteList = container.state.remoteList;
delete remoteList[socketId]
container.setState({ remoteList: remoteList });
container.setState({ info: 'One peer leave!' });
}
socket.on('exchange', function(data) {
exchange(data);
});
socket.on('leave', function(socketId) {
leave(socketId);
});
socket.on('connect', function(data) {
console.log('connected');
});
function initStream() {
getLocalStream(true, function(stream) {
localStream = stream;
container.setState({ selfViewSrc: stream.toURL() });
// container.setState({ status: 'ready', info: 'Please enter or create room ID' });
container.setState({ status: 'connect', info: 'Connecting' });
if (userData.inDanger) {
join(0);
} else {
join(userData.userName);
// join(userData.nowPlaying);
}
});
}
function logError(error) {
console.log("logError", error);
}
function mapHash(hash, func) {
const array = [];
for (const key in hash) {
const obj = hash[key];
array.push(func(obj, key));
}
return array;
}
function _textRoomPress() {
if (!container.textRoomValue) {
return
}
const textRoomData = container.textRoomData.slice();
textRoomData.push({ user: 'Me', message: container.textRoomValue });
for (const key in pcPeers) {
const pc = pcPeers[key];
pc.textDataChannel.send(container.textRoomValue);
}
container.setState({ textRoomData, textRoomValue: '' });
}
function getStats() {
const pc = pcPeers[Object.keys(pcPeers)[0]];
if (pc.getRemoteStreams()[0] && pc.getRemoteStreams()[0].getAudioTracks()[0]) {
const track = pc.getRemoteStreams()[0].getAudioTracks()[0];
console.log('track', track);
pc.getStats(track, function(report) {
console.log('getStats report', report);
}, logError);
}
}
let container;
const Stream = React.createClass({
getInitialState: function() {
this.ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => true });
return {
info: 'Initializing',
status: 'init',
roomID: '',
// isFront: true,
isFront: false,
selfViewSrc: null,
remoteList: {},
textRoomConnected: false,
textRoomData: [],
textRoomValue: '',
};
},
componentDidMount: function() {
container = this;
initStream();
},
_press(event) {
// this.refs.roomID.blur();
this.setState({ status: 'connect', info: 'Connecting' });
join(userData.userName);
// join(this.state.roomID);
},
_switchVideoType() {
const isFront = !this.state.isFront;
this.setState({ isFront });
getLocalStream(isFront, function(stream) {
if (localStream) {
for (const id in pcPeers) {
const pc = pcPeers[id];
pc && pc.removeStream(localStream);
}
localStream.release();
}
localStream = stream;
container.setState({ selfViewSrc: stream.toURL() });
for (const id in pcPeers) {
const pc = pcPeers[id];
pc && pc.addStream(localStream);
}
});
},
receiveTextData(data) {
const textRoomData = this.state.textRoomData.slice();
textRoomData.push(data);
this.setState({ textRoomData, textRoomValue: '' });
},
_textRoomPress() {
if (!this.state.textRoomValue) {
return
}
const textRoomData = this.state.textRoomData.slice();
textRoomData.push({ user: 'Me', message: this.state.textRoomValue });
for (const key in pcPeers) {
const pc = pcPeers[key];
pc.textDataChannel.send(this.state.textRoomValue);
}
this.setState({ textRoomData, textRoomValue: '' });
},
_renderTextRoom() {
return (
<View style={styles.listViewContainer}>
<ListView
dataSource={this.ds.cloneWithRows(this.state.textRoomData)}
enableEmptySections={true}
renderRow={rowData =>
<Text
style={styles.whiteOut}
>{`${rowData.user}: ${rowData.message}`}</Text>}
/>
<TextInput
style={[styles.whiteOut, styles.bgWhite]}
onChangeText={value => this.setState({ textRoomValue: value })}
value={this.state.textRoomValue}
/>
<View style={styles.buttonContainer}>
<TouchableHighlight
style={styles.button}
onPress={this._textRoomPress()}>
<Text style={styles.bgWhite}>Send</Text>
</TouchableHighlight>
</View>
</View>
);
},
render() {
return (
<View style={styles.container}>
{
mapHash(this.state.remoteList, (remote, index) => {
return (
<ScrollView key={index}>
<RTCView key={index} streamURL={this.state.selfViewSrc} style={styles.remoteView}>
<View style={styles.buttonContainer}>
<TouchableHighlight
style={styles.button}
onPress={this._switchVideoType}>
<Text>Switch camera</Text>
</TouchableHighlight>
</View>
<View style={styles.bottomContainer}>
{this.state.textRoomConnected && this._renderTextRoom()}
</View>
</RTCView>
)
})
}
</View>
);
}
});
const styles = StyleSheet.create({
container: {
flex: 10,
// justifyContent: 'center',
backgroundColor: 'rgba(0,0,0, .0)',
},
topContainer: {
flex: 10,
backgroundColor: '#c7c7c7',
},
bottomContainer: {
flex: 1,
justifyContent: 'flex-end',
// backgroundColor: '#ffeeff',
'zIndex': 1,
backgroundColor: 'rgba(0,0,0, .0)',
},
selfView: {
width: 0,
height: 0
},
remoteView: {
flex: 1,
'zIndex': -1,
// backgroundColor: '#c7c7c7',
backgroundColor: '#f0f0f0',
width: width,
height: height - 25,
resizeMode: 'stretch', // or 'stretch'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
listViewContainer: {
height: 150,
},
buttonContainer: {
height: 50,
// backgroundColor: 'powderblue',
justifyContent: 'center',
alignItems: 'center',
},
button: {
marginTop: 50,
marginBottom: 50,
padding: 10,
paddingLeft: 30,
paddingRight: 30,
borderWidth: 1,
borderColor: 'rgba(0, 0, 0, .75)',
},
whiteOut: {
// color: "#ffffff",
color: "#000",
},
bgWhite: {
// backgroundColor: "#ffffff"
},
listView: {
// backgroundColor: "#ffffff",
flex: 10,
// flexDirection: 'row',
// justifyContent: 'center',
// alignItems: 'center',
}
});
export default Stream;
答案 0 :(得分:7)
将其替换为this._textRoomPress.bind(this)
它不是任意射击,每次发出渲染时都会触发。发生这种情况是因为你传递给一个对象作为prop在被传递之前被评估(基本上是一个函数的参数),所以你传递的是函数的返回值,这当然不是你的想。通过传递this._textRoomPress
(如果您想保留对象的上下文,使用可选的bind
),您将传递对该组件稍后将在适当时间调用的函数的引用(当元素被按下时)。
答案 1 :(得分:3)
由于您使用的是createClass而不是es6语法,因此所有方法都已自动绑定到Component。只需将您的onPress更改为:
onPress={this._textRoomPress}>
如果你使用onPress={this._textRoomPress()}>
它会在你的组件被渲染时立即调用该函数。
答案 2 :(得分:2)
在javascript中,你使用<function name>()
来调用一个函数......你在这里做的只是在每次调用_renderTextRoom()
而不是将它分配给onPress道具时调用该函数。我建议你将一个匿名函数作为prop(不调用它)传递,而不是返回this._textRoomPress
的调用。 ES6箭头函数使这非常简单,因为它们不绑定自己的this
more info here
<View style={styles.buttonContainer}>
<TouchableHighlight
style={styles.button}
onPress={() => this._textRoomPress()}>
<Text style={styles.bgWhite}>Send</Text>
</TouchableHighlight>
</View>