Javascript 错误:此.detachTracks不是一个函数-Twilio Video React
接下来,我将修复评论中一些过时的组件,我能够将本地和远程曲目连接到Twilio,但只有在房间中有参与者的情况下分离时才会出现错误。你知道怎么解决这个问题吗 完全错误:Javascript 错误:此.detachTracks不是一个函数-Twilio Video React,javascript,reactjs,twilio,Javascript,Reactjs,Twilio,接下来,我将修复评论中一些过时的组件,我能够将本地和远程曲目连接到Twilio,但只有在房间中有参与者的情况下分离时才会出现错误。你知道怎么解决这个问题吗 完全错误: TypeError: this.detachTracks is not a function Room.onParticipantUnpublishedTrack C:/Users/.../CallRoom.js:87 84 | } 85 | 86 | onParticipantUnpublishedTrack(tr
TypeError: this.detachTracks is not a function
Room.onParticipantUnpublishedTrack
C:/Users/.../CallRoom.js:87
84 | }
85 |
86 | onParticipantUnpublishedTrack(track, trackPublication) {
> 87 | this.detachTracks([track]);
| ^ 88 | }
89 |
90 | roomJoined(room) {
CallRoom.leaveRoom
C:/Users/.../CallRoom.js:43
40 | }
41 |
42 | leaveRoom() {
> 43 | this.state.activeRoom.disconnect();
| ^ 44 | this.setState({ hasJoinedRoom: false, localMediaAvailable: false });
45 | }
46 |
import React, { Component } from 'react';
import Video from 'twilio-video';
import { withRouter } from "react-router-dom";
import { functions } from "../../Fire.js";
class CallRoom extends Component {
constructor(props) {
super(props);
this.joinRoom = this.joinRoom.bind(this);
this.leaveRoom = this.leaveRoom.bind(this);
this.roomJoined = this.roomJoined.bind(this);
this.detachTracks = this.detachTracks.bind(this);
this.detachParticipantTracks =this.detachParticipantTracks.bind(this);
this.state = {
identity: null,
roomName: '',
roomNameErr: false, // Track error for room name TextField
previewTracks: null,
localMediaAvailable: false,
hasJoinedRoom: false,
activeRoom: '' // Track the current active room
};
}
joinRoom() {
console.log("Joining room '" + this.props.match.params.questionId + "'...");
// grabToken call
functions.httpsCallable('grabToken ')(this.props.user.uid).then((response) => {
console.log(response.data.token)
// Join the Room with the token from the server and the
// LocalParticipant's Tracks.
Video.connect(response.data.token, {name: this.props.match.params.questionId}).then(this.roomJoined, error => {
console.error('Could not connect to Twilio: ' + error.code + " - " + error.message);
});
});
}
leaveRoom() {
this.state.activeRoom.disconnect();
this.setState({ hasJoinedRoom: false, localMediaAvailable: false });
}
getTracks(participant) {
return Array.from(participant.tracks.values()).filter(function (publication) {
return publication.track;
}).map(function (publication) {
return publication.track;
});
}
attachTracks(tracks, container) {
tracks.forEach(track => {
container.appendChild(track.attach());
});
}
detachTracks(tracks) {
for (let track of tracks) {
const htmlElements = track.detach();
for (let htmlElement of htmlElements) {
htmlElement.remove();
}
}
}
// Attaches a track to a specified DOM container
attachParticipantTracks(participant, container, isLocal) {
var tracks = this.getTracks(participant);
this.attachTracks(tracks, container, isLocal);
}
detachParticipantTracks(participant) {
var tracks = this.getTracks(participant);
this.detachTracks(tracks);
}
onParticipantDisconnected(participant, error) {
// When a (remote) participant disconnects, detach the associated tracks
this.detachParticipantTracks(participant);
}
onParticipantUnpublishedTrack(track, trackPublication) {
this.detachTracks([track]);
}
roomJoined(room) {
// Called when a participant joins a room
console.log("Joined as '" + this.props.user.uid + "'");
this.setState({
activeRoom: room,
localMediaAvailable: true,
hasJoinedRoom: true
});
// Attach LocalParticipant's Tracks, if not already attached.
var previewContainer = this.refs.localMedia;
if (!previewContainer.querySelector('video')) {
this.attachParticipantTracks(room.localParticipant, previewContainer);
}
// Attach the Tracks of the room's participants.
room.participants.forEach(participant => {
console.log("Already in Room: '" + participant.identity + "'");
var previewContainer = this.refs.remoteMedia;
this.attachParticipantTracks(participant, previewContainer);
});
// Participant joining room
room.on('participantConnected', function (participant) {
console.log("Joining: '" + participant.identity + "'");
participant.tracks.forEach(publication => {
if (publication.isSubscribed) {
const track = publication.track;
document.getElementById('remote-media').appendChild(track.attach());
}
});
participant.on('trackSubscribed', function (track) {
document.getElementById('remote-media').appendChild(track.attach());
});
});
// Attach participant’s tracks to DOM when they add a track
room.on('trackAdded', (track, participant) => {
console.log(participant.identity + ' added track: ' + track.kind);
var previewContainer = this.refs.remoteMedia;
this.attachTracks([track], previewContainer);
});
// Detach participant’s track from DOM when they remove a track.
room.on('trackRemoved', (track, participant) => {
console.log(participant.identity + ' removed track: ' + track.kind);
this.detachTracks([track]);
});
room.on('participantDisconnected', this.onParticipantDisconnected);
room.on('trackUnsubscribed', this.onParticipantUnpublishedTrack);
// Once the local participant leaves the room, detach the Tracks
// of all other participants, including that of the LocalParticipant.
room.on('disconnected', () => {
if (this.state.previewTracks) {
this.state.previewTracks.forEach(track => {
track.stop();
});
}
this.detachParticipantTracks(room.localParticipant);
room.participants.forEach(this.detachParticipantTracks);
this.setState({
activeRoom: null
})
this.setState({ hasJoinedRoom: false, localMediaAvailable: false });
});
}
render() {
// Only show video track after user has joined a room
let showLocalTrack = this.state.localMediaAvailable ? (
<div className="flex-item">
<div ref="localMedia" />
</div>
) : '';
// Hide 'Join Room' button if user has already joined a room.
let joinOrLeaveRoomButton = this.state.hasJoinedRoom ? (
<button className="s-btn-danger" onClick={this.leaveRoom}>Leave Room</button>
) : (
<button className="s-btn" onClick={this.joinRoom}>Join Room</button>
);
return (
<div className="flex-container">
{showLocalTrack}
<div className="flex-item">
{joinOrLeaveRoomButton}
</div>
<div className="flex-item" ref="remoteMedia" id="remote-media" />
</div>
);
}
}
export default withRouter(CallRoom);
{
"name": "app_name",
"version": "0.1.0",
"private": true,
"dependencies": {
"firebase": "^7.2.3",
"formik": "^2.0.3",
"react": "^16.11.0",
"react-burger-menu": "^2.6.11",
"react-confirm": "^0.1.18",
"react-dnd": "^5.0.0",
"react-dnd-html5-backend": "^3.0.2",
"react-dom": "^16.11.0",
"react-firebase-file-uploader": "^2.4.3",
"react-flexbox-grid": "^2.1.2",
"react-ga": "^2.7.0",
"react-icons": "^3.8.0",
"react-modal": "^3.11.1",
"react-responsive": "^8.0.1",
"react-router-dom": "^5.1.2",
"react-scripts": "^3.3.0",
"react-star-ratings": "^2.3.0",
"react-stripe-elements": "^6.0.1",
"react-sweet-progress": "^1.1.2",
"react-toastify": "^5.4.0",
"react-with-separator": "^1.2.0",
"twilio-video": "^2.0.1",
"yup": "^0.27.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
反应成分:
TypeError: this.detachTracks is not a function
Room.onParticipantUnpublishedTrack
C:/Users/.../CallRoom.js:87
84 | }
85 |
86 | onParticipantUnpublishedTrack(track, trackPublication) {
> 87 | this.detachTracks([track]);
| ^ 88 | }
89 |
90 | roomJoined(room) {
CallRoom.leaveRoom
C:/Users/.../CallRoom.js:43
40 | }
41 |
42 | leaveRoom() {
> 43 | this.state.activeRoom.disconnect();
| ^ 44 | this.setState({ hasJoinedRoom: false, localMediaAvailable: false });
45 | }
46 |
import React, { Component } from 'react';
import Video from 'twilio-video';
import { withRouter } from "react-router-dom";
import { functions } from "../../Fire.js";
class CallRoom extends Component {
constructor(props) {
super(props);
this.joinRoom = this.joinRoom.bind(this);
this.leaveRoom = this.leaveRoom.bind(this);
this.roomJoined = this.roomJoined.bind(this);
this.detachTracks = this.detachTracks.bind(this);
this.detachParticipantTracks =this.detachParticipantTracks.bind(this);
this.state = {
identity: null,
roomName: '',
roomNameErr: false, // Track error for room name TextField
previewTracks: null,
localMediaAvailable: false,
hasJoinedRoom: false,
activeRoom: '' // Track the current active room
};
}
joinRoom() {
console.log("Joining room '" + this.props.match.params.questionId + "'...");
// grabToken call
functions.httpsCallable('grabToken ')(this.props.user.uid).then((response) => {
console.log(response.data.token)
// Join the Room with the token from the server and the
// LocalParticipant's Tracks.
Video.connect(response.data.token, {name: this.props.match.params.questionId}).then(this.roomJoined, error => {
console.error('Could not connect to Twilio: ' + error.code + " - " + error.message);
});
});
}
leaveRoom() {
this.state.activeRoom.disconnect();
this.setState({ hasJoinedRoom: false, localMediaAvailable: false });
}
getTracks(participant) {
return Array.from(participant.tracks.values()).filter(function (publication) {
return publication.track;
}).map(function (publication) {
return publication.track;
});
}
attachTracks(tracks, container) {
tracks.forEach(track => {
container.appendChild(track.attach());
});
}
detachTracks(tracks) {
for (let track of tracks) {
const htmlElements = track.detach();
for (let htmlElement of htmlElements) {
htmlElement.remove();
}
}
}
// Attaches a track to a specified DOM container
attachParticipantTracks(participant, container, isLocal) {
var tracks = this.getTracks(participant);
this.attachTracks(tracks, container, isLocal);
}
detachParticipantTracks(participant) {
var tracks = this.getTracks(participant);
this.detachTracks(tracks);
}
onParticipantDisconnected(participant, error) {
// When a (remote) participant disconnects, detach the associated tracks
this.detachParticipantTracks(participant);
}
onParticipantUnpublishedTrack(track, trackPublication) {
this.detachTracks([track]);
}
roomJoined(room) {
// Called when a participant joins a room
console.log("Joined as '" + this.props.user.uid + "'");
this.setState({
activeRoom: room,
localMediaAvailable: true,
hasJoinedRoom: true
});
// Attach LocalParticipant's Tracks, if not already attached.
var previewContainer = this.refs.localMedia;
if (!previewContainer.querySelector('video')) {
this.attachParticipantTracks(room.localParticipant, previewContainer);
}
// Attach the Tracks of the room's participants.
room.participants.forEach(participant => {
console.log("Already in Room: '" + participant.identity + "'");
var previewContainer = this.refs.remoteMedia;
this.attachParticipantTracks(participant, previewContainer);
});
// Participant joining room
room.on('participantConnected', function (participant) {
console.log("Joining: '" + participant.identity + "'");
participant.tracks.forEach(publication => {
if (publication.isSubscribed) {
const track = publication.track;
document.getElementById('remote-media').appendChild(track.attach());
}
});
participant.on('trackSubscribed', function (track) {
document.getElementById('remote-media').appendChild(track.attach());
});
});
// Attach participant’s tracks to DOM when they add a track
room.on('trackAdded', (track, participant) => {
console.log(participant.identity + ' added track: ' + track.kind);
var previewContainer = this.refs.remoteMedia;
this.attachTracks([track], previewContainer);
});
// Detach participant’s track from DOM when they remove a track.
room.on('trackRemoved', (track, participant) => {
console.log(participant.identity + ' removed track: ' + track.kind);
this.detachTracks([track]);
});
room.on('participantDisconnected', this.onParticipantDisconnected);
room.on('trackUnsubscribed', this.onParticipantUnpublishedTrack);
// Once the local participant leaves the room, detach the Tracks
// of all other participants, including that of the LocalParticipant.
room.on('disconnected', () => {
if (this.state.previewTracks) {
this.state.previewTracks.forEach(track => {
track.stop();
});
}
this.detachParticipantTracks(room.localParticipant);
room.participants.forEach(this.detachParticipantTracks);
this.setState({
activeRoom: null
})
this.setState({ hasJoinedRoom: false, localMediaAvailable: false });
});
}
render() {
// Only show video track after user has joined a room
let showLocalTrack = this.state.localMediaAvailable ? (
<div className="flex-item">
<div ref="localMedia" />
</div>
) : '';
// Hide 'Join Room' button if user has already joined a room.
let joinOrLeaveRoomButton = this.state.hasJoinedRoom ? (
<button className="s-btn-danger" onClick={this.leaveRoom}>Leave Room</button>
) : (
<button className="s-btn" onClick={this.joinRoom}>Join Room</button>
);
return (
<div className="flex-container">
{showLocalTrack}
<div className="flex-item">
{joinOrLeaveRoomButton}
</div>
<div className="flex-item" ref="remoteMedia" id="remote-media" />
</div>
);
}
}
export default withRouter(CallRoom);
{
"name": "app_name",
"version": "0.1.0",
"private": true,
"dependencies": {
"firebase": "^7.2.3",
"formik": "^2.0.3",
"react": "^16.11.0",
"react-burger-menu": "^2.6.11",
"react-confirm": "^0.1.18",
"react-dnd": "^5.0.0",
"react-dnd-html5-backend": "^3.0.2",
"react-dom": "^16.11.0",
"react-firebase-file-uploader": "^2.4.3",
"react-flexbox-grid": "^2.1.2",
"react-ga": "^2.7.0",
"react-icons": "^3.8.0",
"react-modal": "^3.11.1",
"react-responsive": "^8.0.1",
"react-router-dom": "^5.1.2",
"react-scripts": "^3.3.0",
"react-star-ratings": "^2.3.0",
"react-stripe-elements": "^6.0.1",
"react-sweet-progress": "^1.1.2",
"react-toastify": "^5.4.0",
"react-with-separator": "^1.2.0",
"twilio-video": "^2.0.1",
"yup": "^0.27.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
看起来您只是忘记了在构造函数中绑定participantUnpublishedTrack。看起来您需要遍历并手动绑定需要使用此
的每个函数,或者将它们转换为箭头函数。我在这里看到几个会抛出错误的leaveRoom
,attachParticipantTracks
,onParticipantDisconnected
你完全正确,让我试试看,谢谢!这解决了问题,谢谢你的额外一双眼睛!