I have two services, one is sending video service and the other is receiving video service.
The server only forwards the information and forwards the information to the other party.
The service that receives the video can receive the video at some times, but most of them cannot.
I don't know where the problem occurred, the service that sends the video or the service that receives the video.
caller
import { useEffect, useRef, useState, useCallback } from "react";
import io from "socket.io-client";
function createPeerConnection() {
const myPeerConnection = new RTCPeerConnection();
return myPeerConnection;
}
async function setLocalStream(myPeerConnection, target) {
console.log("setLocalStream");
const webcamStream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
});
target.srcObject = webcamStream;
webcamStream
.getTracks()
.forEach((track) =>
myPeerConnection.addTransceiver(track, { streams: [webcamStream] })
);
}
const App = () => {
const ref = useRef();
const [socket] = useState(io());
useEffect(() => {
socket.emit("init", "hello");
socket.on("init", (res) => {
console.log(res);
});
}, []);
const handleNegotiationNeededEvent = useCallback(
(myPeerConnection) => async () => {
try {
const offer = await myPeerConnection.createOffer();
await myPeerConnection.setLocalDescription(offer);
console.log(
"send video-offer",
myPeerConnection.localDescription
);
socket.emit("video-offer", myPeerConnection.localDescription);
} catch (error) {
console.error(error);
}
},
[socket]
);
const handleICECandidateEvent = useCallback(
(event) => {
if (event.candidate) {
console.log("send new-ice-candidate", event.candidate);
socket.emit("new-ice-candidate", event.candidate);
}
},
[socket]
);
useEffect(() => {
const myPeerConnection = createPeerConnection();
myPeerConnection.onicecandidate = handleICECandidateEvent;
myPeerConnection.onnegotiationneeded = handleNegotiationNeededEvent(
myPeerConnection
);
setLocalStream(myPeerConnection, ref.current);
socket.on("video-answer", async (sdp) => {
console.log("received video-answer", sdp);
const desc = new RTCSessionDescription(sdp);
try {
await myPeerConnection.setRemoteDescription(desc);
} catch (error) {
console.error(error);
}
});
socket.on("new-ice-candidate", async (c) => {
console.log("received new-ice-candidate", c);
const candidate = new RTCIceCandidate(c);
try {
await myPeerConnection.addIceCandidate(candidate);
} catch (error) {
console.error(error);
}
});
}, []);
return (
<>
<video style={{ width: "10px" }} ref={ref} autoPlay muted />
</>
);
};
export default App;
callee
import { useEffect, useRef, useState, useCallback } from "react";
import io from "socket.io-client";
function createPeerConnection() {
const myPeerConnection = new RTCPeerConnection();
return myPeerConnection;
}
const App = () => {
const ref = useRef();
const [socket] = useState(io());
useEffect(() => {
socket.emit("init", "hello");
socket.on("init", (res) => {
console.log(res);
});
}, []);
const handleICECandidateEvent = useCallback(
(event) => {
if (event.candidate) {
console.log("send new-ice-candidate", event.candidate);
socket.emit("new-ice-candidate", event.candidate);
}
},
[socket]
);
const handleTrackEvent = useCallback((event) => {
ref.current.srcObject = event.streams[0];
}, []);
useEffect(() => {
const myPeerConnection = createPeerConnection();
myPeerConnection.onicecandidate = handleICECandidateEvent;
myPeerConnection.ontrack = handleTrackEvent;
socket.on("video-offer", async (sdp) => {
console.log("received offer", sdp);
const desc = new RTCSessionDescription(sdp);
await myPeerConnection.setRemoteDescription(desc);
await myPeerConnection.setLocalDescription(
await myPeerConnection.createAnswer()
);
console.log("send answer", myPeerConnection.localDescription);
socket.emit("video-answer", myPeerConnection.localDescription);
});
socket.on("new-ice-candidate", async (c) => {
console.log("received new-ice-candidate", c);
const candidate = new RTCIceCandidate(c);
try {
await myPeerConnection.addIceCandidate(candidate);
} catch (error) {
console.error(error);
}
});
}, []);
return (
<>
<video style={{ width: "20px" }} ref={ref} autoPlay />
</>
);
};
export default App;
Related
I have this custom http hook with abort when you try to go to a different page (I saw it in a tutorial but I am not truly sure I need it). When I fetch data with it and useEffect(), I have this error on the backend but the request is executed and everything is as planned. My question is, how to improve my code so it does not throw this error and do I need this functionality with abortController() ?
http-hook.ts
import { useCallback, useRef, useEffect } from "react";
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { selectError, showError } from "src/redux/error";
import { selectLoading, startLoading, stopLoading } from "src/redux/loading";
export const useHttpClient = () => {
const dispatch = useDispatch();
const error = useSelector(selectError);
const loading = useSelector(selectLoading);
const activeHttpRequests: any = useRef([]);
const sendRequest = useCallback(
async (url, method = "GET", body = null, headers = {}) => {
dispatch(startLoading());
const httpAbortCtrl = new AbortController();
activeHttpRequests.current.push(httpAbortCtrl);
try {
const response = await fetch(url, {
method,
body,
headers,
signal: httpAbortCtrl.signal,
});
const responseData = await response.json();
activeHttpRequests.current = activeHttpRequests.current.filter(
(reqCtrl) => reqCtrl !== httpAbortCtrl
);
if (!response.ok) {
throw new Error(responseData.message);
}
dispatch(stopLoading());
return responseData;
} catch (err) {
dispatch(showError(err.message));
dispatch(stopLoading());
throw err;
}
},
[]
);
useEffect(() => {
return () => {
activeHttpRequests.current.forEach((abortCtrl: any) => abortCtrl.abort());
};
}, []);
return { loading, error, sendRequest };
};
UserInfo.tsx
import React, { Fragment, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { useHttpClient } from "src/hooks/http-hook";
import classes from "./UserInfo.module.css";
const UserInfo = () => {
const { sendRequest } = useHttpClient();
const [currentUser, setCurrentUser] = useState<any>();
const userId = useParams<any>().userId;
useEffect(() => {
const fetchCurrentUser = async () => {
try {
const responseData = await sendRequest(
`http://localhost:5000/api/user/${userId}`
);
setCurrentUser(responseData.user);
console.log("currentUser ", currentUser);
} catch (err) {
console.log(err);
}
};
fetchCurrentUser();
}, [sendRequest ,userId]);
return currentUser ? (
<Fragment>
<div className={classes.cover} />
<div className={classes.user_info}>
<img
alt="user_img"
src={`http://localhost:5000/${currentUser.image}`}
className={classes.user_img}
/>
<div className={classes.text}>
<p>
Name: {currentUser.name} {currentUser.surname}
</p>
<p>Email: {currentUser.email}</p>
<p>Age: {currentUser.age}</p>
</div>
</div>{" "}
</Fragment>
) : (
<p>No current user</p>
);
};
export default UserInfo;
Backend
getCurrentUser.ts controller
const getCurrentUser = async (
req: express.Request,
res: express.Response,
next: express.NextFunction
) => {
const userId = req.params.userId;
let user;
try {
user = await User.findById(userId);
} catch (err) {
const error = new HttpError("Could not fetch user", 500);
return next(error);
}
res.json({ user: user.toObject({ getters: true }) });
};
How would I avoid the infinite loop issue?
I'm getting an error while rendering the following component:
Too many re-renders. React limits the number of renders to prevent an infinite loop.?
TeamContent.js re-renders multiple times, how can I set an initial render on load?
Error given
TeamContent.js
import { useEffect, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
fetchTeamPlayers,
fetchUpcomingGames,
fetchPreviousGames,
fetchLiveGames,
} from "../../../data/UserInfo/infoActions";
import TeamPlayers from "./TeamPlayers";
import TeamNext from "./TeamNext";
import TeamPrevious from "./TeamPrevious";
import LiveEvent from "./Live.js/LiveEvent";
function TeamContent(props) {
console.log("test");
let containsLiveGame = false;
const dispatch = useDispatch();
const liveGames = useSelector((store) => store.userInfo.live.games.all);
const status = useSelector((store) => store.userInfo.playersLoadStatus);
const UpcomingGamesstatus = useSelector(
(store) => store.userInfo.upcomingGamesStatus
);
const previousGamesStatus = useSelector(
(store) => store.userInfo.previousGamesStatus
);
const liveStatus = useSelector((store) => store.userInfo.live.games.status);
liveGames.map((game) => {
const verifyHomeTeam = +game.idHomeTeam === +props.teamID;
const verifyAwayTeam = +game.idAwayTeam === +props.teamID;
if (verifyAwayTeam || verifyHomeTeam) {
containsLiveGame = true;
}
});
// -----> request team data
useEffect(() => {
dispatch(fetchTeamPlayers(props.teamID));
dispatch(fetchUpcomingGames(props.teamID));
dispatch(fetchPreviousGames(props.teamID));
dispatch(fetchLiveGames());
}, [dispatch, props.teamID]);
useEffect(() => {
dispatch(fetchLiveGames());
const interval = setInterval(() => {
dispatch(fetchLiveGames());
}, 30000);
return () => clearInterval(interval);
}, [dispatch]);
return (
<div className="teamDash">
<div className="dashLeft">
<div
className="dashLeftHead"
style={{
backgroundImage: `url(${props.stadiumImg})`,
}}
>
<div className="dashLeftHeadAbs"></div>
<div className="dashLeftHeadIntro">
<span>{props.stadiumName}</span>
<h3>{props.teamName}</h3>
</div>
</div>
{liveStatus !== "error" && containsLiveGame && <LiveEvent />}
{status !== "error" && (
<div className="dashLeftPlayers">
<TeamPlayers />
</div>
)}
<div className="dashLeftDesc">
<p>{props.teamDesc}</p>
</div>
</div>
<div className="dashRight">
{UpcomingGamesstatus === "error" ? (
console.log("unable to load upcoming games")
) : (
<div className="upcomingGames">
<TeamNext id={props.teamID} />
</div>
)}
{previousGamesStatus === "error" ? (
console.log("unable to load previous games")
) : (
<div className="previousGames">
<TeamPrevious />
</div>
)}
</div>
</div>
);
}
export default TeamContent;
infoActions.js
import { API_URL } from "../Api";
import { infoActions } from "./infoSlice";
export function fetchTeams() {
return (dispatch) => {
dispatch(infoActions.loadStatusHandler({ status: "loading" }));
async function getTeams() {
try {
const rq = await fetch(`${API_URL}Lookup_all_teams.php?id=4387`);
const res = await rq.json();
const data = res.teams;
dispatch(infoActions.loadTeamsHandler({ teams: data }));
dispatch(infoActions.loadStatusHandler({ status: "done" }));
} catch (error) {
dispatch(infoActions.loadStatusHandler({ status: "error" }));
}
}
getTeams();
};
}
export function fetchTeamPlayers(id) {
return (dispatch) => {
async function getPlayers() {
dispatch(infoActions.statusPlayersHandler({ status: "loading" }));
try {
const rq = await fetch(`${API_URL}lookup_all_players.php?id=${id}`);
const res = await rq.json();
const data = res.player;
dispatch(infoActions.loadPlayersHandler({ players: data }));
dispatch(infoActions.statusPlayersHandler({ status: "done" }));
} catch (error) {
dispatch(infoActions.statusPlayersHandler({ status: "error" }));
}
}
getPlayers();
};
}
export function fetchUpcomingGames(id) {
return (dispatch) => {
dispatch(infoActions.statusUGHandler({ status: "loading" }));
async function getGames() {
try {
const rq = await fetch(`${API_URL}eventsnext.php?id=${id}`);
const res = await rq.json();
const data = res.events;
dispatch(infoActions.upcomingGamesHandler({ games: data }));
dispatch(infoActions.statusUGHandler({ status: "done" }));
} catch (error) {
dispatch(infoActions.statusUGHandler({ status: "error" }));
}
}
getGames();
};
}
export function fetchPreviousGames(id) {
return (dispatch) => {
dispatch(infoActions.statusPGHandler({ status: "loading" }));
async function getGames() {
try {
const rq = await fetch(`${API_URL}eventslast.php?id=${id}`);
const res = await rq.json();
const data = res.results;
dispatch(infoActions.previousGamesHandler({ games: data }));
dispatch(infoActions.statusPGHandler({ status: "done" }));
} catch (error) {
dispatch(infoActions.statusPGHandler({ status: "error" }));
}
}
getGames();
};
}
export function fetchLiveGames() {
return (dispatch) => {
dispatch(infoActions.statusLiveGames({ status: "loading" }));
async function getGames() {
try {
const rq = await fetch(
`https://www.thesportsdb.com/api/v2/json/40130162/livescore.php?l=4387`
);
const res = await rq.json();
const data = res.events;
dispatch(infoActions.statusLiveGames({ status: "done" }));
dispatch(infoActions.loadLiveGames({ liveGames: data }));
} catch (error) {
dispatch(infoActions.statusLiveGames({ status: "error" }));
}
}
getGames();
};
}
Try remove dispatch from the array you passed to
useEffect(() => {
...
}, [dispatch, props.teamID])
and
useEffect(() => {
...
}, [dispatch])
dispatch is a function, and if you include it into the useEffect listener, the useEffect will trigger on every render
I have a component that loads data from an API which I mocked for my test but it is not loaded as the test cannot find the element which contain the data.
component:
import { useDispatch, useSelector } from "react-redux";
import { useState, useEffect, useCallback } from "react";
import { businessDataActions } from "../store/business-data";
import { fetchBusinessListing } from "../services/business-listing";
import styles from "../styles/BizCard.module.css";
import BizCardItem from "./BizCardItem";
const BizCard = (props) => {
const dispatch = useDispatch();
const [listing, setListing] = useState([]);
//load all listing
const fetchListing = useCallback(async () => {
dispatch(businessDataActions.setIsLoading({ isLoading: true }));
const ListingService = await fetchBusinessListing();
if (ListingService.success) {
setListing(ListingService.data);
} else {
dispatch(
businessDataActions.setNotify({
severity: "error",
message: "Problem when fetching listing.",
state: true,
})
);
}
dispatch(businessDataActions.setIsLoading({ isLoading: false }));
}, []);
useEffect(() => {
fetchListing();
}, []);
const businessList = listing.map((item) => (
<BizCardItem
key={item.key}
id={item.id}
name={item.name}
shortDescription={item.shortDescription}
imageUrl={item.imageUrl}
/>
));
return (
<div className={styles.grid} role="grid">
{businessList}
</div>
);
};
test file:
const bizListing = [
...some fake data
];
jest.mock("../../services/business-listing", () => {
return function fakeListing() {
return { success: true, data: bizListing };
}
});
afterEach(cleanup);
describe('BizCard', () => {
test("loading listing", async () => {
useSession.mockReturnValueOnce([null, false]);
await act(async () => {render(
<BizCard />
)});
const itemGrid = await screen.findAllByRole("gridcell");
expect(itemGrid).not.toHaveLength(0);
});
});
services/business-listing:
export const fetchBusinessListing = async() => {
try {
const response = await fetch(
"/api/business"
);
if (!response.ok) {
throw new Error('Something went wrong!');
}
const data = await response.json();
const loadedBusiness = [];
for (const key in data) {
let imgUrl =
data[key].imageUrl !== "undefined" && data[key].imageUrl !== ""
? data[key].imageUrl
: '/no-image.png';
loadedBusiness.push({
key: data[key]._id,
id: data[key]._id,
name: data[key].businessName,
shortDescription: data[key].shortDescription,
imageUrl: imgUrl,
});
}
return { success: true, data: loadedBusiness };
} catch (error) {
return ({success: false, message: error.message});
}
}
The test executed with these returned:
TypeError: (0 , _businessListing.fetchBusinessListing) is not a function
48 | // }
49 |
> 50 | const ListingService = await fetchBusinessListing();
Unable to find role="gridcell"
I can confirm gridcell is rendered when I am using browser.
Can anyone please shed some light on my problem
Manage to solve the problem myself, problem is with the mock:
jest.mock("../../services/business-listing", () => {
return {
fetchBusinessListing: jest.fn(() => { return { success: true, data: bizListing }}),
}
});
Im having trouble trying to stop the current playing sound when another Sound is pressed without having to pause the current Sound in react Native Expo. Note: I can pause and play the Sound perfectly. So basically like a normal music player if that is overlapping when pressing another song.
const SampleTrack = {uri:'https://firebasestorage.googleapisro-b97ec.appspot.com/o/song%201.mp3?a9'}
const FirstP = () => {
const [Loaded, SetLoaded] = React.useState(false);
const [Loading, SetLoading] = React.useState(false);
const sound = React.useRef(new Audio.Sound());
React.useEffect(() => {
LoadAudio();
}, []);
const PlayAudio = async () => {
try {
const result = await sound.current.getStatusAsync();
if (result.isLoaded) {
if (result.isPlaying === false) {
sound.current.playAsync();
}
}
} catch (error) {}
};
const PauseAudio = async () => {
try {
const result = await sound.current.getStatusAsync();
if (result.isLoaded) {
if (result.isPlaying === true) {
sound.current.pauseAsync();
}
}
} catch (error) {}
};
const LoadAudio = async () => {
SetLoading(true);
const checkLoading = await sound.current.getStatusAsync();
if (checkLoading.isLoaded === false) {
try {
const result = await sound.current.loadAsync(SampleTrack, {}, true);
if (result.isLoaded === false) {
SetLoading(false);
console.log('Error in Loading Audio');
} else {
SetLoading(false);
SetLoaded(true);
}
} catch (error) {
console.log(error);
SetLoading(false);
}
} else {
SetLoading(false);
}
};
if anyone can help that would be great.
Here's a complete Audio Player with Play/Pause/Load/Next/Previous feature.
Working Example
import * as React from 'react';
import {
Text,
View,
StyleSheet,
ActivityIndicator,
Button,
} from 'react-native';
import Constants from 'expo-constants';
import { Audio } from 'expo-av';
const Tracks = [
{
id: 0,
track: require('./Roses.m4a'),
},
{
id: 1,
track: require('./Poison.m4a'),
},
{
id: 2,
track: require('./Alone.m4a'),
},
];
export default function App() {
const [Loaded, SetLoaded] = React.useState(false);
const [Loading, SetLoading] = React.useState(false);
const [CurrentSong, SetCurrentSong] = React.useState(Tracks[0]);
const sound = React.useRef(new Audio.Sound());
React.useEffect(() => {
LoadAudio();
return () => Unload();
}, [CurrentSong]);
const Unload = async () => {
await sound.current.unloadAsync();
};
const PlayAudio = async () => {
try {
const result = await sound.current.getStatusAsync();
if (result.isLoaded) {
if (result.isPlaying === false) {
sound.current.playAsync();
}
}
} catch (error) {
console.log(error);
}
};
const PauseAudio = async () => {
try {
const result = await sound.current.getStatusAsync();
if (result.isLoaded) {
if (result.isPlaying === true) {
sound.current.pauseAsync();
}
}
} catch (error) {
console.log(error);
}
};
const LoadAudio = async () => {
SetLoaded(false);
SetLoading(true);
const checkLoading = await sound.current.getStatusAsync();
if (checkLoading.isLoaded === false) {
try {
const result = await sound.current.loadAsync(
CurrentSong.track,
{},
true
);
if (result.isLoaded === false) {
SetLoading(false);
console.log('Error in Loading Audio');
} else {
SetLoading(false);
PlayAudio();
SetLoaded(true);
}
} catch (error) {
console.log(error);
SetLoading(false);
}
} else {
SetLoading(false);
}
};
const NextSong = () => {
if (CurrentSong.id === Tracks[Tracks.length - 1].id) {
SetCurrentSong(Tracks[0]);
} else {
SetCurrentSong(Tracks[CurrentSong.id + 1]);
}
};
const PrevSong = () => {
if (CurrentSong.id === 0) {
SetCurrentSong(Tracks[Tracks.length - 1]);
} else {
SetCurrentSong(Tracks[CurrentSong.id - 1]);
}
};
return (
<View style={styles.container}>
<View style={styles.AudioPLayer}>
{Loading === true ? (
<ActivityIndicator size={'small'} color={'red'} />
) : (
<>
<Button title="Play Song" onPress={PlayAudio} />
<Button title="Pause Song" onPress={PauseAudio} />
<Text>Currently Playing : {CurrentSong.id}</Text>
<Button title="Next Song" onPress={NextSong} />
<Button title="Previous Song" onPress={PrevSong} />
</>
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
AudioPLayer: {
width: '100%',
height: 50,
alignItems: 'center',
},
});
I am trying to pull data from an Axios Get. The backend is working with another page which is a React component.
In a function however, it doesn't work. The length of the array is not three as it is supposed to be and the contents are empty.
I made sure to await for the axios call to finish but I am not sure what is happening.
import React, { useState, useEffect } from "react";
import { Container } from "#material-ui/core";
import ParticlesBg from "particles-bg";
import "../utils/collagestyles.css";
import { ReactPhotoCollage } from "react-photo-collage";
import NavMenu from "./Menu";
import { useRecoilValue } from "recoil";
import { activeDogAtom } from "./atoms";
import axios from "axios";
var setting = {
width: "300px",
height: ["250px", "170px"],
layout: [1, 3],
photos: [],
showNumOfRemainingPhotos: true,
};
const Collages = () => {
var doggies = [];
//const [dogs, setData] = useState({ dogs: [] });
const dog = useRecoilValue(activeDogAtom);
const getPets = async () => {
try {
const response = await axios.get("/getpets");
doggies = response.data;
//setData(response.data);
} catch (err) {
// Handle Error Here
console.error(err);
}
};
useEffect(() => {
const fetchData = async () => {
getPets();
};
fetchData();
}, []);
return (
<>
<NavMenu />
<ParticlesBg type="circle" margin="20px" bg={true} />
<br></br>
<div>
{doggies.length === 0 ? (
<div>Loading...</div>
) : (
doggies.map((e, i) => {
return <div key={i}>{e.name}</div>;
})
)}
</div>
<Container align="center">
<p> The length of dogs is {doggies.length} </p>
<h1>Knight's Kennel</h1>
<h2> The value of dog is {dog}</h2>
<h2>
Breeders of high quality AKC Miniature Schnauzers in Rhode Island
</h2>
<section>
<ReactPhotoCollage {...setting} />
</section>
</Container>
</>
);
};
export default Collages;
Try doing the following:
const [dogs, setData] = useState([]);
[...]
const getPets = async () => {
try {
const response = await axios.get("/getpets");
doggies = response.data;
setData(response.data);
} catch (err) {
// Handle Error Here
console.error(err);
}
};
const fetchData = async () => {
getPets();
};
useEffect(() => {
fetchData();
}, []);
No idea if it will actually work, but give it a try if you haven't.
If you don't use useState hook to change the array, it won't update on render, so you will only see an empty array on debug.
As far as I can tell you do not return anything from the getPets() function.
Make use of the useState Function to save your doggies entries:
let [doggies, setDoggies ] = useState([]);
const getPets = async () => {
try {
const response = await axios.get("/getpets");
return response.data;
} catch (err) {
// Handle Error Here
console.error(err);
}
return []
};
useEffect(() => {
setDoggies(await getPets());
});
I used setState inside the getPets function. Now it works.
const Collages = () => {
const [dogs, setData] = useState([]);
const dog = useRecoilValue(activeDogAtom);
const getPets = async () => {
try {
const response = await axios.get("/getpets");
setData(response.data);
} catch (err) {
// Handle Error Here
console.error(err);
}
};
useEffect(() => {
const fetchData = async () => {
getPets();
};
fetchData();
}, []);