ontrack is not firing in webrtc - reactjs

I am making a video calling application using react , webrtc and firebase. I am able to connect both local and remote connection but i am not receiving the remote mediastream. The ontrack function is not firing and i don't know why.
import logo from './logo.svg';
import { useEffect, useRef } from 'react';
import './App.css';
import { useState } from 'react';
import { initializeApp } from 'firebase/app'
import { addDoc, collection, doc, getDoc, getFirestore, onSnapshot, setDoc, updateDoc } from 'firebase/firestore'
function App() {
const myVideoRef = useRef(null)
const yourVideoRef = useRef(null)
const [cameras, setcameras] = useState()
const [myCallId, setmyCallId] = useState()
const [callId, setcallId] = useState()
const [roomId ,setroomId] = useState()
const servers = {
iceServers: [
{
urls: ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302'],
},
],
iceCandidatePoolSize: 10,
}
const pc = new RTCPeerConnection(servers)
const firebaseConfig = {
// my config
}
const app = initializeApp(firebaseConfig)
const db = getFirestore(app)
async function getConnectedDevices(type){
const devices = await navigator.mediaDevices.enumerateDevices()
return devices.filter(device => device.kind === type)
}
async function openCamera(cameraId){
const constraints = {
'audio': {'echoCancellation': true},
'video': {
'deviceId': cameraId,
}
}
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
stream.getTracks().forEach((track) => {
pc.addTrack(track,stream)
})
myVideoRef.current.srcObject = stream
})
// this part is not firing.
let remoteStream = new MediaStream()
pc.ontrack = (event) => {
event.streams[0].getTracks().forEach((track) => {
remoteStream.addTrack(track)
})
}
yourVideoRef.current.srcObject = remoteStream
}
async function call(){
const callDoc = doc(collection(db,"calls"))
const offerCandidates = collection(callDoc,"offerCandidates")
const answerCandidates = collection(callDoc,"answerCandidates")
setmyCallId(callDoc.id)
pc.onicecandidate = (event) => {
console.log(event.candidate)
event.candidate && addDoc(offerCandidates,event.candidate.toJSON())
}
const offerDescription = await pc.createOffer()
await pc.setLocalDescription(offerDescription)
const offer = {
sdp: offerDescription.sdp,
type: offerDescription.type
}
await setDoc(callDoc, { offer } )
onSnapshot(callDoc, snapshot => {
const data = snapshot.data()
if(!pc.currentRemoteDescription && data?.answer){
const answerDescription = new RTCSessionDescription(data.answer)
pc.setRemoteDescription(answerDescription)
}
})
onSnapshot(answerCandidates, snapshot => {
snapshot.docChanges().forEach((change) => {
if(change.type === 'added'){
console.log(change.doc.data())
const candidate = new RTCIceCandidate(change.doc.data())
pc.addIceCandidate(candidate)
console.log(yourVideoRef.current.srcObject)
console.log(myVideoRef.current.srcObject)
}
})
})
}
async function answer(){
const callDoc = doc(collection(db,"calls"),callId)
const offerCandidates = collection(callDoc,"offerCandidates")
const answerCandidates = collection(callDoc,"answerCandidates")
pc.onicecandidate = (event) => {
event.candidate && addDoc(answerCandidates,event.candidate.toJSON())
}
const callData = (await getDoc(callDoc)).data()
console.log(callData)
const offerDescription = callData.offer
await pc.setRemoteDescription(new RTCSessionDescription(offerDescription))
const answerDescription = await pc.createAnswer()
await pc.setLocalDescription(answerDescription)
const answer = {
type: answerDescription.type,
sdp: answerDescription.sdp,
}
await updateDoc(callDoc, {answer})
onSnapshot(offerCandidates, snapshot => {
snapshot.docChanges().forEach((change) => {
console.log(change)
if(change.type === 'added'){
let data = change.doc.data()
pc.addIceCandidate(new RTCIceCandidate(data))
}
})
})
}
useEffect(() => {
async function fetch(){
const cameras = await getConnectedDevices('videoinput')
setcameras(cameras)
}
fetch()
},[])
return (
<div className="App">
<div className='flex flex-row'>
{cameras && cameras.map( camera => <h2 className='m-3' key={camera.deviceId} onClick={() => openCamera(camera.deviceId)} >{camera.label}</h2>)}
</div>
<div className='flex flex-row'>
<video className='w-1/2' ref={myVideoRef} autoPlay />
<video className='w-1/2' ref={yourVideoRef} autoPlay />
</div>
<button onClick={call} className='bg-gray-200'>Call</button>
<div className='flex flex-row'>
<input onChange={(e) => setcallId(e.target.value)} className='border-[4px] border-black' />
<button onClick={answer} className='bg-gray-200'>Answer</button>
</div>
<h2>{myCallId}</h2>
</div>
);
}
export default App;
The ontrack function is not firing. I have put the function in useEffect , on top outside all the functions, before setremotedescription but it is still not firing.
let remoteStream = new MediaStream()
pc.ontrack = (event) => {
event.streams[0].getTracks().forEach((track) => {
remoteStream.addTrack(track)
})
}
yourVideoRef.current.srcObject = remoteStream

Related

TypeError: "function" is not a function

Currently trying to learn React and I am making a video calling web app. The whole purpose of the web app is to simply enter in a session together with another person and share your video and audio. However I am encountering the following issue:
TypeError: sendStream is not a function
Apparently the function sendStream is not a function, that function is assigned to a button and the way it should work is that everytime we click on "Share my video" the video and the audio of the other person who is also in the same session should be shared.
Here they are:
sendStream
const sendStream = async(stream) => {
const tracks = stream.getTracks();
for(const track of tracks){
peer.addTrack(track,stream);
}
};
where it is used
return(
<div className='session-page-container'>
<h1>Hi mom, Im on TV :D</h1>
<h4>You are now online with {remoteUserID}</h4>
<button onClick={(e) => sendStream(myStream)}>Share my video</button>
<ReactPlayer url={myStream} playing muted/>
<ReactPlayer url={remoteStream} playing/>
</div>
)
The entire components
** File Peer.jsx (where the function sendStream is created**
import React, { useMemo, useEffect, useState, useCallback } from "react";
const peerContext = React.createContext(null);
export const usePeer = () => React.createContext(null);
export const PeerProvider = (props) => {
const [remoteStream, setRemoteStream] = useState(null);
const peer = useMemo(() =>
new RTCPeerConnection({
iceServers: [
{
urls: [
"stun:stun.l.google.com:19302",
"stun:global.stun.twilio.com:3478",
],
},
],
}),
[]
);
const createOffer = async() => {
const offer = await peer.createOffer();
await peer.setLocalDescription(offer);
return offer;
};
const createAnswer = async (offer) => {
await peer.setRemoteDescription(offer);
const answer = await peer.createAnswer();
await peer.setLocalDescription(answer);
return answer;
};
const setRemoteAns = async(ans) =>{
await peer.setRemoteDescription(ans);
};
const sendStream = async(stream) => {
const tracks = stream.getTracks();
for(const track of tracks){
peer.addTrack(track,stream);
}
};
const handleTrackEvent = useCallback((ev) =>{
const streams = ev.streams;
setRemoteStream(streams[0]);
}, []);
useEffect(() => {
if (!peer) return
peer.addEventListener("track",handleTrackEvent);
return () =>{
peer.removeEventListener("track",handleTrackEvent)
}
},[handleTrackEvent, peer]);
return(
<peerContext.Provider value={{ peer, createOffer, createAnswer, setRemoteAns, sendStream,remoteStream}}>{props.children}</peerContext.Provider>
);
};
File Session.jsx where it is used
import React, {useEffect, useCallback, useState} from 'react';
import ReactPlayer from "react-player";
import { useSocket} from "../providers/Socket";
import { usePeer } from "../providers/Peer";
const SessionPage = () => {
const { socket } = useSocket();
const { peer, createOffer, createAnswer,setRemoteAns,sendStream,remoteStream } = usePeer();
const [myStream,setMyStream] = useState(null);
const [remoteUserID, setRemoteUserID] = useState();
const handleNewUserJoined = useCallback(
async(data) =>{
const {userID} = data
console.log("New user joined the session",userID);
const offer = await createOffer();
socket.emit('call-user',{ userID, offer });
setRemoteUserID(userID);
},
[createOffer,socket]
);
const handleIncomingCall = useCallback( async(data) => {
const {from, offer} = data;
console.log("Incoming Call from", from, offer);
const ans = await createAnswer(offer);
socket.emit("call-accepted",{userID: from, ans});
setRemoteUserID(from);
},
[createAnswer, socket] );
const handleCallAccepted = useCallback(async(data) => {
const {ans} = data;
console.log("Call Got Accepted",ans);
await setRemoteAns(ans);
}, [setRemoteAns]);
const getUserMediaStream = useCallback(async() => {
const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
setMyStream(stream);
}, []);
const handleNegotiation = useCallback(() => {
const localOffer = peer.localDescription;
socket.emit("call-user",{userID: remoteUserID, offe: localOffer });
}, []);
useEffect(() => {
socket.on("user-joined",handleNewUserJoined);
socket.on("incomming-call",handleIncomingCall);
socket.on("call-accepted",handleCallAccepted);
//return () =>{
// socket.off("user-joined",handleNewUserJoined);
//socket.off("incomming-call", handleIncomingCall);
//socket.off("call-accepted",handleCallAccepted);
//};
}, [handleCallAccepted,handleIncomingCall, handleNewUserJoined, socket]);
/*useEffect(() => {
peer.addEventListener("negationneeded",handleNegotiation);
return () =>{
peer.removeEventListener("negotionneeded",handleNegotiation);
};
},[]);*/
useEffect(() => {
getUserMediaStream();
},[]);
return(
<div className='session-page-container'>
<h1>Hi mom, Im on TV :D</h1>
<h4>You are now online with {remoteUserID}</h4>
<button onClick={(e) => sendStream(myStream)}>Share my video</button>
<ReactPlayer url={myStream} playing muted/>
<ReactPlayer url={remoteStream} playing/>
</div>
)
}
export default SessionPage
Can anyone please help me out and make sure that this work the way it should work?
You are creating two different contexts here:
const peerContext = React.createContext(null);
export const usePeer = () => React.createContext(null);
It should be:
const peerContext = React.createContext(null);
export const usePeer = () => useContext(peerContext);

SWAPI React - InfiniteScroll

I'm trying to play with the Star Wars API and set Infinite Scroll, but I can't handle adding more pages. I'm displaying the first page.
I know I'm doing something wrong in the getMorePeople function, but I have no idea how to change it. Could someone suggest something?
import {useEffect, useState} from "react";
import axios from "axios";
const swapi = axios.create({
baseURL: "https://swapi.dev/api/"
});
const InfiniteScroll = () => {
const [people, setPeople] = useState([]);
const [page, setPage] = useState(1);
const peopleApi = swapi.get(`people/?page=${page}`);
const fetchPeople = async () => {
const response = await peopleApi;
const transformPeople = response.data.results.map(PeopleObject => {
return {
name: PeopleObject.name,
height: PeopleObject.height,
hair_color: PeopleObject.hair_color,
skin_color: PeopleObject.skin_color,
birth_year: PeopleObject.birth_year
}
})
setPeople(transformPeople);
}
useEffect(() => {
fetchPeople();
}, []);
const getMorePeople = async (page, people = []) => {
const {next, results} = await fetchPeople(people);
people = [...people, ...results];
if (next !== null) {
return getMorePeople(next, people);
}
return people;
}
return (
<>
<div>
{people.map((onePerson) => {
return (
<div key={onePerson.name}>
<p: {onePerson.name}</p>
<p>Height: {onePerson.height}</p>
<p>Hair color: {onePerson.hair_color}</p>
<p>Skin color: {onePerson.skin_color}</p>
<p>Birth year: {onePerson.birth_year}</p>
</div>
)
})}
<button onClick={getMorePeople}>Next</button>
</div>
</>
)
};
export default InfiniteScroll;
Check if this suits your needs:
import { useEffect, useState } from "react";
import axios from "axios";
const swapi = axios.create({
baseURL: "https://swapi.dev/api/"
});
const InfiniteScroll = () => {
const [people, setPeople] = useState([]);
const [page, setPage] = useState(1);
const fetchPeople = async (page = 1) => {
const response = await swapi.get(`people/?page=${page}`);;
const transformPeople = response.data.results.map(PeopleObject => {
return {
name: PeopleObject.name,
height: PeopleObject.height,
hair_color: PeopleObject.hair_color,
skin_color: PeopleObject.skin_color,
birth_year: PeopleObject.birth_year
}
})
setPeople([...people, ...transformPeople]); //append the new page into the existing array
}
useEffect(() => {
fetchPeople();
}, []);
const getMorePeople = async () => {
const nextPage = page + 1;
setPage(nextPage);
fetchPeople(nextPage);
}
return (
<>
<div>
{people.map((onePerson) => {
return (
<div key={onePerson.name}>
<p> {onePerson.name}</p>
<p>Height: {onePerson.height}</p>
<p>Hair color: {onePerson.hair_color}</p>
<p>Skin color: {onePerson.skin_color}</p>
<p>Birth year: {onePerson.birth_year}</p>
<br />
</div>
)
})}
<button onClick={getMorePeople}>Next</button>
</div>
</>
)
};
export default InfiniteScroll;

ReactJS Error when using map function, cannot read properties of undefined

I'm trying to make a sport/tinder like app for a school project from a friend of mine. It came together well on my localhost, but for him it was a requirement to host it online. Not really a professional in hosting, but I was a bit familiar with Heroku. I used a client and a server side for my application, so I build the client side and put it into the server side folder. This server side is hosted on the Heroku page. But whenever I try to login, it won't work and I get this error message in my console.
TypeError: Cannot read properties of undefined (reading 'map')
The error says it is caused by this line of code.
const matchedUserIds = matches.map(({user_id}) => user_id)
This is the whole MatchDisplay file that is used in my Dashboard. I'm using a MongoDB for the storage of my users.
import axios from "axios";
import { useEffect, useState } from "react";
import { useCookies } from "react-cookie";
const MatchesDisplay = ({ matches, setClickedUser }) => {
const [matchedProfiles, setMatchedProfiles] = useState(null);
const [cookies, setCookie, removeCookie] = useCookies(null);
const [matched, setMatched] = useState(null);
const matchedUserIds = matches.map(({ user_id }) => user_id);
const userId = cookies.UserId;
const getMatches = async () => {
try {
const response = await axios.get(
"https://[app].herokuapp.com/users",
{
params: { userIds: JSON.stringify(matched()) },
}
);
setMatchedProfiles(response.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getMatches();
}, [matches]);
const filteredMatchedProfiles = matchedProfiles?.filter(
(matchedProfile) =>
matchedProfile.matches.filter(
(profile) => profile.user_id === userId
).length > 0
);
return (
<div className="matches-display">
{filteredMatchedProfiles?.map((match) => (
<div
key={match.user_id}
className="match-card"
onClick={() => setClickedUser(match)}
>
<div className="img-container">
<img
src={match?.url}
alt={match?.first_name + "profile"}
/>
</div>
<h3>{match?.first_name}</h3>
</div>
))}
</div>
);
};
export default MatchesDisplay;
Any help is welcome. If you need more code examples, please reply ;)
EDIT
The ChatContainer that passes the user to the MatchesDisplay.
import ChatHeader from "./ChatHeader";
import MatchesDisplay from "./MatchesDisplay";
import ChatDisplay from "./ChatDisplay";
import { useState } from 'react';
const ChatContainer = ({user}) => {
const [ clickedUser, setClickedUser] = useState(null)
return (
<div className="chat-container">
<ChatHeader user={user}/>
<div>
<button className="option" onClick={() => setClickedUser(null)}>Matches</button>
<button className="option" disabled={!clickedUser}>Chat</button>
<button className="option" >Prices</button>
</div>
{!clickedUser && <MatchesDisplay matches={user.matches} setClickedUser={setClickedUser}/>}
{clickedUser && <ChatDisplay user={user} clickedUser={clickedUser}/>}
</div>
)
}
export default ChatContainer
The Dashboard that passes the user to the Chatcontainer.
import TinderCard from 'react-tinder-card';
import {useEffect, useState} from 'react';
import {useCookies} from 'react-cookie';
import ChatContainer from '../components/ChatContainer'
import axios from "axios";
const Dashboard = () => {
const [user, setUser] = useState(null)
const [genderedUsers, setGenderedUsers] = useState(null)
const [lastDirection, setLastDirection] = useState(null)
const [cookies, setCookie, removeCookie] = useCookies(['user'])
const [matchedUserIds, setMatchedUserIds] = useState(null)
const [filteredGenderedUsers, setFilteredGenderedUsers] = useState(null)
const userId = cookies.UserId
const getUser = async () => {
try {
const response = await axios.get('https://funfit-webpage.herokuapp.com/user', {
params: {userId}
})
return setUser(response.data)
} catch (error) {
console.log(error)
}
}
const getGenderedUsers = async () => {
try {
const response = await axios.get('https://funfit-webpage.herokuapp.com/gendered-users', {
params: {gender: user?.gender_interest}
})
return setGenderedUsers(response.data)
} catch (error) {
console.log(error)
}
}
useEffect(() => {
getUser()
}, [])
useEffect(() => {
setMatchedUserIds(user?.matches.map(({user_id}) => user_id).concat(userId))
if (user) return getGenderedUsers()
}, [user])
useEffect(() => {
if (genderedUsers) {
return setFilteredGenderedUsers(genderedUsers?.filter(
genderedUser => !matchedUserIds.includes(genderedUser.user_id)
))
}
}, [genderedUsers])
const updateMatches = async (matchedUserId) => {
try {
await axios.put('https://funfit-webpage.herokuapp.com/addmatch', {
userId,
matchedUserId
})
return getUser()
} catch (error) {
console.log(error)
}
}
const swiped = (direction, swipedUserId) => {
console.log(direction, swipedUserId)
if (direction === 'right') {
updateMatches(swipedUserId)
}
return setLastDirection(direction)
}
const outOfFrame = (name) => {
console.log(name + ' left the screen!')
}
return (<>
{user && <div className="dashboard">
<ChatContainer user={user}/>
<div className="swipe-container">
<div className="card-container">
{filteredGenderedUsers?.map((genderedUser) =>
<TinderCard
className='swipe'
key={genderedUser.user_id}
onSwipe={(dir) => swiped(dir, genderedUser.user_id)}
onCardLeftScreen={() => outOfFrame(genderedUser.first_name)}>
<div style={{backgroundImage: 'url(' + genderedUser.url + ')'}} className='card'>
<h3>{'Name: ' + genderedUser.first_name} <br/> {'Sport: ' + genderedUser.about}</h3>
</div>
</TinderCard>)}
<div className="swipe-info">
{lastDirection ? <p>You swiped {lastDirection}</p> : <p/>}
</div>
</div>
</div>
</div>}
</>)
}
export default Dashboard

empty cart, firebase-firestore react-hooks

I'm developing an ecommerce app with Firestore.
When a user deletes an item or adds an item - it's rendering properly.
But when I'm trying to empty the whole cart (delete doc), it's just not rendering without refresh.
Maybe it's about the deleted doc, so the the function cannot find the doc because there is no doc?
If so, what would be best practice solution here?
Here is the code:
import React, { useState, useEffect } from 'react'
import firebase from 'firebase';
import { useAuth, useStoreUpdate } from '../contexts/FirebaseContext';
import { Link, useHistory } from 'react-router-dom';
import 'react-responsive-modal/styles.css';
import { Modal } from 'react-responsive-modal';
export default function Cart() {
const [userMail, setUserMail] = useState(undefined)
const [userCart, setUserCart] = useState(undefined)
const [totalAmmout, setTotalAmmout] = useState(0)
const user = useAuth()
const userDoc = firebase.firestore().collection("cart").doc(userMail)
const updateStore = useStoreUpdate()
const [open, setOpen] = useState(false);
const onOpenModal = () => setOpen(true);
const onCloseModal = () => setOpen(false);
const history = useHistory()
const emptyCart = async () => {
await userDoc.delete()
await updateCart()
await console.log('ksaljdklasd');
await updateStore()
await console.log('dasdsad');
}
const updateCart = () => {
userDoc.get().then((doc) => {
if (doc.exists) {
let cart = doc.data()
setUserCart(cart)
}
})
}
const updateData = async () => {
if (user.currentUser) {
await updateCart()
if (userCart) {
let totalPrice = 0;
await userCart.item.forEach(item => {
totalPrice += item.price
})
await setTotalAmmout(totalPrice)
}
}
}
async function removeFromCart(itemId, name, url, price, category, type, description) {
const cartItem = { itemId, name, url, price, category, type, description }
await userDoc.update({
item: firebase.firestore.FieldValue.arrayRemove(cartItem)
})
await updateCart()
await updateStore()
}
useEffect(() => {
if (user.currentUser) {
setUserMail(user.currentUser.email);
updateStore();
}
}, []);
useEffect(() => {
updateData().then(
console.log(totalAmmout)
)
}, userCart);
if (!userCart) return <h1>hold</h1>
return (
<main className="main-cart">
<div className="container">
{userCart.item && userCart.item.length >= 1 && userCart.item.map((item) => {
return (
< div className="item-container" key={item.itemId} >
<h3>{item.name}</h3>
<p>${item.price}</p>
<img height="150px" width="150px" src={item.url} alt="" />
<button onClick={async () => {
await removeFromCart(item.itemId, item.name, item.url, item.price, item.category, item.type, item.description)
}}>X</button>
</div>
)
})}
</div>
<button className="fixed-bottom-link" onClick={onOpenModal}>finish</button>
<Modal showCloseIcon={true} open={open} onClose={onCloseModal} center>
<div className="modal-container">
<div>
{userCart &&
userCart.item.map(item => {
return (
<li>{item.name} <span className="strong">{'|$' + item.price}</span></li>
)
})
}
{totalAmmout &&
<h3>total price: ${totalAmmout}</h3>
}
</div>
<button onClick={emptyCart}>Click to Pay</button>
</div>
</Modal>
</main >
)
}
just had to reset the doc :
befor :
const emptyCart = async () => {
await userDoc.delete()
await updateCart()
await updateStore()
}
after :
const emptyCart = async () => {
const userDoc = await firebase.firestore().collection("cart").doc(userMail)
await userDoc.delete()
await userDoc.set({
item: firebase.firestore.FieldValue.arrayUnion()
})
await updateCart()
await updateStore()
}

How can I upload a image file using and react Socket-IO?

i want to make a chat app with react and socket.io
i downloaded code from https://github.com/adrianhajdin/project_chat_application.
I want to add upload file function using socketio_file_upload
but when i upload the img. there is nothing happen..
this is my code
index.js (server)
const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const siofu = require("socketio-file-upload");
const { addUser, removeUser, getUser, getUsersInRoom } = require('./users');
const PORT = process.env.PORT || 5000
const router = require('./router')
const app = express()
console.log(app,'------------------app----------')
const server = http.createServer(app)
const io = socketio(server)
io.on('connection', (socket)=>{
const uploader = new siofu();
uploader.dir = "/uploads";
uploader.listen(socket);
uploader.on("saved", function(event){
});
uploader.on("error", function(event){
});
socket.on('join', ({name, room}, callback)=>{
const { user, error } = addUser({ id:socket.id, name, room })
if(error) {
return callback(error)
}
//admin system정보 여기서
socket.emit('message', { user:'admin', text:`${user.name}, welcome to the room ${user.room}` })
//braodcast는 room에 있는 모든 사람에게 msg를 보낸다.
socket.broadcast.to(user.room).emit('message', { user: 'admin', text: `${user.name} has joined!` });
socket.join(user.room)
io.to(user.room).emit('roomData', {room: user.room, users: getUsersInRoom(user.room)})
callback()
})
socket.on('sendMessage', (message, callback) => {
const user = getUser(socket.id);
io.to(user.room).emit('message', { user: user.name, text: message });
io.to(user.room).emit('roomData', { room: user.room, users: getUsersInRoom(user.room)});
callback();
});
socket.on('disconnect', () => {
const user = removeUser(socket.id)
io.to(user.room).emit('message', { user:'admin', text: `${user.name} has left`})
})
})
app.use(siofu.router)
server.listen(PORT, ()=> console.log('---SERVER START---'))
Chat.jsx
import React, { useState, useEffect, useRef } from 'react';
import queryString from 'query-string'
import io from 'socket.io-client'
import './chat.css'
import InfoBar from '../InfoBar/InfoBar'
import Messages from '../Messages/Messages'
import Input from '../Input/Input'
let socket ='default'
const Chat = ({location}) => {
const [name, setName] = useState('');
const [room, setRoom] = useState('');
const [message, setMessage] = useState('')
const [messages, setMessages] = useState([])
const END_POINT = 'localhost:5000'
//componentdidmount와 같다
useEffect(()=>{
const {name, room} = queryString.parse(location.search)
socket = io(END_POINT)
setName(name)
setRoom(room)
//server에 join을 통해서 데이터를 보냄
socket.emit('join', {name, room}, (res)=>{
})
//useEffect()애서 return 은 unmount와 같다. 즉 user leave일 때 사용!
return () =>{
socket.emit('disconnect')
socket.off()
}
},[END_POINT, location.search])
useEffect(() => {
socket.on('message', (message) =>{
setMessages([...messages, message])
})
// uploader.listenOnInput(document.getElementById("siofu_input"));
}, [messages])
const sendMessage = (event) => {
event.preventDefault();
if(message) {
socket.emit('sendMessage', message, () => setMessage(''));
}
}
return (
<div className="outerContainer">
<div className="container">
<InfoBar room={room} />
<Messages messages={messages} name={name} />
<Input socket={socket} message={message} setMessage={setMessage} sendMessage={sendMessage} />
</div>
</div>
);
};
export default Chat;
Input.jsx
import React, { Component } from 'react';
import SocketIOFileUpload from '../../../../server/node_modules/socketio-file-upload'
import './input.css';
class Input extends Component {
uploadFile = (e) => {
const {socket} = this.props
console.log("uploading");
// const files = e.target.files;
const siofu = new SocketIOFileUpload(socket);
siofu.listenOnInput(document.getElementById("siofu_input"));
};
render() {
const { setMessage, sendMessage, message, socket } = this.props
return (
<form className="form">
<input
className="input"
type="text"
placeholder="Type a message..."
value={message}
onChange={({ target: { value } }) => setMessage(value)}
onKeyPress={event => event.key === 'Enter' ? sendMessage(event) : null}
/>
<input type="file" id="siofu_input" onChange={this.uploadFile.bind(this)}/>
<button className="sendButton" onClick={e => sendMessage(e)}>Send</button>
</form>
);
}
}
export default Input;
users.js
const users = [];
const addUser = ({ id, name, room }) => {
name = name.trim().toLowerCase();
room = room.trim().toLowerCase();
const existingUser = users.find((user) => user.room === room && user.name === name);
if(!name || !room) return { error: 'Username and room are required.' };
if(existingUser) return { error: 'Username is taken.' };
const user = { id, name, room };
users.push(user);
return { user };
}
const removeUser = (id) => {
const index = users.findIndex((user) => user.id === id);
if(index !== -1) return users.splice(index, 1)[0];
}
const getUser = (id) => users.find((user) => user.id === id);
const getUsersInRoom = (room) => users.filter((user) => user.room === room);
module.exports = { addUser, removeUser, getUser, getUsersInRoom };
How can i upload img file to chat app....
At first, you must create "uploads" folder to upload files.
When I run the app on local, I created folder on to D drive and changed uploader.dir from '/uploads' to "uploads";
At second, when you select DOM, you used document.elementById, this is wrong, must use ref={(el)=>this.variable=el} and change to siofu.listenOnInput(this.variable);
At third, you did define upload logic in onChange event listener, have to define in componentDidMount().

Resources