功能触发时它想要。我该怎么解决这个问题?

时间:2016-12-12 17:47:31

标签: javascript reactjs react-native ecmascript-6 ecmascript-7

我有这个视频,在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;

3 个答案:

答案 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>