I am implementing a real time chat app using react and node but struggling with sending messages to the server. Below is my Chat component where socket connection with the server starts.
The problem is when I hit the send button, sendMsg runs and gives me an error TypeError: Cannot read property 'emit' of undefined. socket is assigned the return values of socketIOClient(ENDPOINT)inside useEffect but seems to stay undefined at the time of hitting the send button. I guess
Can someone please help me fix this?
import React, { useState, useEffect } from 'react';
import socketIOClient from "socket.io-client";
import Button from '#material-ui/core/Button';
import Box from '#material-ui/core/Box';
import Loading from './Loading';
import TextField from '#material-ui/core/TextField';
import { Container, Typography } from '#material-ui/core';
import { Fragment } from 'react';
import queryString from 'query-string';
import { Redirect } from 'react-router-dom';
const ENDPOINT = "http://localhost:4001";
const Chat = ({location}) =>{
const [msgList, setMsgList] = useState([]);
const [name, setName] = useState(null);
let socket;
useEffect(()=>{
const {name} = queryString.parse(location.search);
setName(name)
socket = socketIOClient(ENDPOINT);
socket.emit("setName", name)
if(socket){
socket.on("greeting", (data)=>{
setMsgList(msgList => [...msgList, {type: "server", msg:data}]);
console.log(msgList)
})
}
return()=>{
if(socket){
socket.disconnect();
}
}
},[location.search, name])
const sendMsg = (event)=>{
event.preventDefault();
console.log(socket)
socket.emit("message", {msg: event.target.message.value})
}
return (
<Fragment>
<Container >
<Box maxWidth="600px" height="100vh" marginX="auto" marginY="0" textAlign="center" position="relative">
<Box paddingY="15px">
<Typography variant="h4">Let's Chat!</ Typography>
</Box>
<Box>
{msgList.map((msgObj, index)=>{
return <p key={index + 1}>{msgObj.type}: {msgObj.msg}</p>
})}
</Box>
<Box position="absolute" bottom="0" left="0"width="100%" zIndex="10">
<form autoComplete="off" onSubmit={sendMsg}>
<TextField name="message" label="say something" variant="outlined" fullWidth />
<Button type="submit" color="secondary" fullWidth variant="contained">Send</Button>
</form>
</Box>
</Box>
</Container>
</Fragment>
);
}
export default Chat;
Related
After using the BrowserRouter as a wrapper function nothing is displayed on the webpage.
App.js
import React, { Component } from 'react';
import './App.css';
import Homepage from './components/homepage/homepage';
import Login from './components/login/login';
import Register from './components/register/register';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
// <div className="App">
<Router>
<div className="App">
<ul >
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/login">Login</Link>
</li>
<li>
<Link to="/register">Register</Link>
</li>
</ul>
<Routes>
<Route exact path='/' element={< Homepage />}></Route>
<Route exact path='/login' element={< Login />}></Route>
<Route exact path='/register' element={< Register />}></Route>
</Routes>
</div>
</Router>
// </div>
);
}
export default App;
homepage.js
import React from "react"
import "./homepg.css"
const Homepage = () => {
return (
<div className="homepage">
<h1>Hello Homepage</h1>
<div className="button">Logout</div>
</div>
)
}
export default Homepage
login.js
import React, {useState} from "react"
import "./login.css"
import axios from "axios"
const Login = () => {
const [ user, setUser ] = useState({
email : "",
password : ""
})
const handleChange = e => {
const {name , value} = e.target
setUser({
...user,
[name] : value
})
}
const login = () => {
axios.post("http://localhost:9002/login",user)
.then(res => alert(res.data.message))
}
return (
<div className="login">
{console.log("User",user)}
<h1>Login</h1>
<input type="text" name="email" value={user.email} placeholder="Enter email" onChange={handleChange}></input>
<input type="password" name="password" value={user.password} placeholder="Enter password" onChange={handleChange}></input>
<div className="button" onClick={login}>Login</div>
<div>or</div>
<div className="button">Register</div>
</div>
)
}
export default Login
register.js
import React, {useState} from "react"
import "./register.css"
import axios from "axios"
const Register = () => {
const [ user, setUser ] = useState({
name: "",
email : "",
password : "",
reEnterPassword : ""
})
const handleChange = e => {
const {name , value} = e.target
setUser({
...user,
[name] : value
})
}
const register = () =>{
const {name,email,password, reEnterPassword} = user
if(name && email && password && (password === reEnterPassword)){
axios.post("http://localhost:9002/register", user)
// console.log("yo")
.then(res => console.log(res))
}
else{
alert("Invalid input")
}
}
return (
<div className="register">
{console.log("User",user)}
<h1>Register</h1>
<input type="text" name="name" value={user.name} placeholder="Your Name" onChange={handleChange}></input>
<input type="text" name="email" value={user.email} placeholder="Your Email" onChange={handleChange}></input>
<input type="password" name="password" value={user.password} placeholder="Your password" onChange={handleChange}></input>
<input type="password" name="reEnterPassword" value={user.reEnterPassword} placeholder="Re-enter password" onChange={handleChange}></input>
<div className="button" onClick={register}>Register</div>
<div>or</div>
<div className="button">Login</div>
</div>
)
}
export default Register
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<App />,
);
If only <Homepage />, <Login/>, and <Register /> are present then homepage, login, and register page gets displayed.
But once I use the Router from react-router-dom then the webpage is blank, nothing is displayed.
There are several reasons why your components are not being displayed when using the BrowserRouter component from the react-router-dom library. Some of the most common reasons include:
1. Incorrect Router Import: Make sure you have imported the BrowserRouter component correctly from the react-router-dom library. The correct import statement is: import { BrowserRouter } from 'react-router-dom'.
2. Wrapping the Wrong Components: Make sure that you are wrapping the correct components inside the BrowserRouter. The BrowserRouter should wrap all the components that need access to the routing functionality.
3. Incorrect Route Configuration: Make sure you have correctly set up your routes using the Route component. The Route component should be used to define the mapping between a path and a component.
4. Components not Exporting Correctly: Make sure that your components are being exported correctly. Each component should be exported using export default ComponentName.
If you provide more information about your code and the error message that you're encountering, I'd be happy to help you further.
After getting data from the backend, I can't get to display is on the homepage
Everthing is okay like server, database but conditional rendering is not working
Homepage UI with error
`
import React, {useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getAllPizzas } from "../actions/pizzaActions";
import Error from "../components/Error";
import Loading from "../components/Loading";
import Pizza from "../components/Pizza";
const Homescreen = () => {
const dispatch = useDispatch();
const pizzasstate = useSelector((state) => state.getAllPizzasReducer);
const { pizzas, error, loading } = pizzasstate;
useEffect(() => {
dispatch(getAllPizzas());
}, [dispatch]);
return (
<div>
<div className="row">
{loading ? (
<Loading/>
) : error ? (
<Error error='Something went wrong'/>
) : (
pizzas.map((pizza) => {
return (
<div className="col-md-3 m-3" key={pizza._id}>
<div>
<Pizza pizza={pizza} />
</div>
</div>
);
})
)}
</div>
</div>
);
};
export default Homescreen;
Thank you in advance
I want to take the data response from the Axios post, and display it on the page:
import React, { useRef} from 'react';
import logo from './assets/img/lupa.png';
import { Form } from "#unform/web";
import Input from './components/forms/input';
import * as Yup from "yup";
import './App.css';
import axios from 'axios';
function App() {
const formRef = useRef(null);
async function handleSubmit(data, ){
try{
const schema = Yup.object().shape({
nn: Yup.number().min(8,"O campo eh obrigatorio e precisa ter 8 ou mais caracteres")
})
await schema.validate(data)
console.log(data)
}catch(err){
if(err instanceof Yup.ValidationError){
console.log(err)
}}
axios.post("http://localhost:8080/api", data).then(res => console.log(res.data))
.catch(err => console.log(err));
}
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>$ Search $</h2>
</div>
<Form ref={formRef} onSubmit={handleSubmit}>
<Input name="nn" type="number"/>
<button type='submit'>buscar</button>
</Form>
</div>
);
}
export default App;
But I don't know how to work with that res.data and how to display it on the page by the jsx react, I tried to use useState and set it in the axios.post("http://localhost:8080/api", data).then(res => setState(res.data))
.catch(err => console.log(err)); - but when I console.log someState it brings an object null, i tried to display on the page using
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>$ Search $</h2>
</div>
<Form ref={formRef} onSubmit={handleSubmit}>
<Input name="nn" type="number"/>
<button type='submit'>buscar</button>
</Form>
{
someState.length >=1 ? someState.map((some, idx) =>{
return <p key={idx}>{some.data}</p>
})
: ""
}
</div>
);
}
but nothing were display! ( If you have some suggestion to change of the overall code, you can answer too ), How can I fix this 2 problems ? I want to learn moreThe first object Im printing my input, to check if it are working, and the second object its what I recieved from the axios post response(.then(res => console.log(res.data), I want to display this object "resultado"
Object { nn: "00000000353" }
Object { ip: "200.1******", resultado: 961 }
ip: "200.1*****"
resultado: 961
<prototype>: Object { … }
See this nice post by digitalOcean How to use axios in ReactJs
https://www.digitalocean.com/community/tutorials/react-axios-react
Hope you got a lot of help from this post.
I am currently trying to build a connection between a Node.js application in the backend and a React application in the frontend. The connection from the frontend to the backend seems to work without any problems. Unfortunately, the React application, on the other side, cannot accept any data.
The socket.on(...) function throws an error:
dashboard.js:20 Uncaught TypeError: Cannot read properties of null (reading 'on')
I can not explain where the error lies.
app.js (mounting point of the React app):
import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import io from 'socket.io-client';
import Dashboard from "./compontents/views/dashboard/dashboard";
function App() {
const [socket, setSocket] = useState(null);
useEffect(() => {
const newSocket = io(`http://${window.location.hostname}:8040`);
setSocket(newSocket);
return () => newSocket.close();
}, [setSocket]);
return (
<Router>
<div className="app">
<div className="app__view">
<Switch>
<Route exact path="/">
<Dashboard socket={socket} />
</Route>
</Switch>
</div>
</div>
</Router>
);
}
export default App;
dashboard.js (child component):
import React, { useEffect, useState } from 'react';
import { Link } from "react-router-dom";
import FeatherIcon from 'feather-icons-react';
import LargeButton from "../../buttons/largeButton/largeButton";
function Dashboard({ socket }) {
function toggleLight(type) {
if(type) {
// this function works fine
socket.emit("toggle light", type);
console.log(type);
}
}
useEffect(() => {
// this line is causing the error
socket.on('toggle button', (type) => {
console.log(type);
});
}, [socket]);
return(
<div className="view">
<div className="all">
<LargeButton icon="sun" text="Alles einschalten" event={toggleLight} />
<LargeButton icon="moon" text="Alles ausschalten" event={toggleLight} />
</div>
</div>
)
}
export default Dashboard;
It seems like your <Dashboard/> component are mounting before the socket instance are ready to go. Socket connection is an a async procedure so you must take this on mind when you use it.
Try change your app.js to this:
import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import io from 'socket.io-client';
import Dashboard from './compontents/views/dashboard/dashboard';
function App() {
const [socket, setSocket] = useState(null);
useEffect(() => {
const newSocket = io(`http://${window.location.hostname}:8040`);
setSocket(newSocket);
return () => newSocket.close();
}, [setSocket]);
if (!socket) {
// catch and show some loading screen
// while the socket connection gets ready
return <div>Loading...</div>;
}
return (
<Router>
<div className="app">
<div className="app__view">
<Switch>
<Route exact path="/">
<Dashboard socket={socket} />
</Route>
</Switch>
</div>
</div>
</Router>
);
}
I used CRA to create simple Login form. I've set up database with mongoose and built crud with node.
I don't think it has anything to do with the backend.
My intention with this little boiler plate was:
(not logged in) -> landing page shows 'Welcome' with Home, sign in menu.
(logged in) -> landing page shows 'Welcome, name' with Home, MyPage menu.
Down below is Login.js.
import React, { useState } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import "../App.css";
function Login() {
const [Email, setEmail] = useState("");
const [Password, setPassword] = useState("");
const [Error, setError] = useState("");
const onEmailHandler = (e) => {
setEmail(e.currentTarget.value);
};
const onPasswordHandler = (e) => {
setPassword(e.currentTarget.value);
};
const onSubmitHandler = (e) => {
e.preventDefault();
const body = {
email: Email,
password: Password,
};
axios
.post("/api/users/login", body)
.then((response) => {
if (!response.data.token) {
setError(response.data.error);
} else {
window.location.replace("/");
//props.history.push("/");
}
})
.catch((e) => {
console.log(e);
});
};
return (
<div>
<div>
<form className="login_form">
<input
type="email"
placeholder="Email"
onChange={onEmailHandler}
value={Email}
/>
<br />
<input
type="password"
placeholder="Password"
onChange={onPasswordHandler}
value={Password}
/>
<br />
<button onClick={onSubmitHandler}>Login</button>
</form>
</div>
<div
style={{
marginTop: 14,
fontSize: 15,
color: "red",
fontFamily: "Arial",
fontWeight: "lighter",
}}
>
{Error}
</div>
<div className="register_button">
<Link to="/register">Sign Up</Link>
</div>
</div>
);
}
export default Login;
As you can see, when you are signed in properly you are thrown to the landing page.
landing page looks like this.
import React, { useState } from "react";
import "../App.css";
import axios from "axios";
function Landing() {
const [Nickname, setNickname] = useState("");
axios.get("/api/users/authenticate").then((response) => {
if (response.data.name) {
setNickname(response.data.name);
}
});
return Nickname === "" ? (
<div className="welcome_msg">
<h4>Welcome!</h4>
</div>
) : (
<div className="welcome_msg">
<h4>Welcome, {Nickname}!</h4>
</div>
);
}
export default Landing;
And most importantly, App.js looks like down below.
import React, { useEffect, useState } from "react";
import { Route, BrowserRouter, Link } from "react-router-dom";
import "./App.css";
import axios from "axios";
import Landing from "./components/Landing";
import Login from "./components/Login";
import MyPage from "./components/MyPage";
import Register from "./components/Register";
function App() {
const [IsLoggedIn, setIsLoggedIn] = useState(false);
axios.get("/api/users/authenticate").then(
(response) => {
if (response.data.email) {
setIsLoggedIn(true);
} else {
setIsLoggedIn(false);
}
console.log(IsLoggedIn);
}
//[IsLoggedIn]
);
return IsLoggedIn ? (
<BrowserRouter>
<nav className="navigate">
<Link to="/">Home</Link>
<Link to="/mypage">Mypage</Link>
<hr />
</nav>
<Route exact path="/" component={Landing} />
<Route path="/login" component={Login} />
<Route path="/mypage" component={MyPage} />
<Route path="/register" component={Register} />
</BrowserRouter>
) : (
<BrowserRouter>
<nav className="navigate">
<Link to="/">Home</Link>
<Link to="/login">Sign in</Link>
<hr />
</nav>
<Route exact path="/" component={Landing} />
<Route path="/login" component={Login} />
<Route path="/mypage" component={MyPage} />
<Route path="/register" component={Register} />
</BrowserRouter>
);
}
export default App;
The Router api/user/authenticate returns json with user information(email, name, token).
It's not like there's an error to the app, but I think maybe it's re-rendered too many times? It's slow and doesn't work like a spa page. I've checked the network tab and there seems to be too many requests (mostly authentication) whenever i go to Home or Mypage.
Stay safe, stay away from virus and please help :(
That's because the submit handler must be passed to the form itself as an onSubmit method instead of the onClick of the button.
<form className="login_form" onSubmit={onSubmitHandler}>
...
</form>