Reputation: 1727
I have created chat application using reactjs, nodejs, mongodb. I am storing the data in mongodb but while mapping over messages array it doesn't show messages in chat app why so ?
I am using message
state variable to store single message and all these single messages are added inside messages
array (state variable
). I set message: "" and date : ""
but what is happening in my case even before displaying message on screen it is set to empty string. How can I map over messages and display all messages in chat app ?
Code:
server.js:
const express = require('express');
const mongoose = require('mongoose');
const socket = require('socket.io');
const message = require('./model/message')
const app = express();
const mongoURI = require('./config/keys').mongoURI;
mongoose.connect(mongoURI, {useNewUrlParser: true}, function (err,res) {
if(err){
console.log("There is error: " + err);
}else{
console.log("Connected to mongo database")
}
})
let db = mongoose.connection;
db.once('open', function() {
console.log("Database is now connected");
let io = socket(server);
io.on("connection", function(socket){
console.log("Socket Connection Established with ID :"+ socket.id)
socket.on('disconnect', function(){
console.log('User Disconnected');
});
let chat = db.collection('chat');
socket.on('SEND_MESSAGE', function(data){
let message = data.message;
let date = data.date;
// Check for name and message
if(message !== '' || date !== ''){
// Insert message
chat.insert({message: message, date:date}, function(){
socket.emit('RECEIVE_MESSAGE', [data]);
});
}
});
chat.find().sort({_id:1}).toArray(function(err, res){
if(err){
throw err;
}
// Emit the messages
socket.emit('RECEIVE_MESSAGE', res);
});
})
});
const port = 5000;
let server = app.listen(5000, function(){
console.log('server is running on port 5000')
});
messages.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const MessageSchema = new Schema({
message: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Message', MessageSchema);
chat.js:
import React, { Component } from 'react'
import './chat.css'
import io from "socket.io-client";
export default class Chat extends Component {
constructor(props){
super(props);
this.state = {
message: '',
date: '',
messages: []
};
this.sendMessage = this.sendMessage.bind(this);
this.addMessage = this.addMessage.bind(this);
this.socket = io('localhost:5000');
}
componentDidMount() {
this.socket.on('RECEIVE_MESSAGE', data => {
this.addMessage(data);
});
}
sendMessage(event) {
event.preventDefault();
if(this.state.message !== ''){
this.socket.emit('SEND_MESSAGE', {
message: this.state.message,
date: Date.now()
});
}
};
addMessage(data) {
this.setState({
messages: [...this.state.messages, data],
message: '',
date: ''
});
console.log(this.state.messages);
};
render() {
return (
<div>
<div id="status"></div>
<div id="chat">
<div className="card">
<div id="messages" className="card-block">
{this.state.messages.map((message, index) => {
return (
<div key={index} className="msgBox"><p className="msgText">{message.message}</p></div>
)
})}
</div>
</div>
<div className="row">
<div className="column">
<input id="inputmsg" type="text" placeholder="Enter Message...."
value={this.state.message} onChange={ev => this.setState({message: ev.target.value})}/>
</div>
<div className="column2">
<button id="send" className="button" onClick={this.sendMessage}>Send</button>
</div>
</div>
</div>
</div>
)
}
}
Screenshot of console.log(this.state.messages)
:
Upvotes: 0
Views: 338
Reputation: 226
Judging from your server side code it looks like you do emit RECEIVE_MESSAGE
as an array and so doing [ ...state.messages, data ]
results in multidimensional array being created in react. You can either emit a single message via RECEIVE_MESSAGE
or change your addMessage
to do [ ...state.messages, ...data ]
.
To explain this more:
So at first your messages
state is set to an empty array. Then all your old messages comes from socket as an array (data) and addMessage
gets called and tries to spread elements of state.messages
(which is still empty at this point) and then adds a data
(which is an array) in the end of that new array being set to state. The result is that you get an array with one element: all your previous messages (array in array). When new message comes in addMessage
does the same spreading and so state.messages
gets spread into a new array and data
(which is again - an array) gets added to the end of it. The result is array with two elements: the first array (data) that got added in the beginning and the new one. By doing ...data
in addMessage
function you're spreading the actual array of data and putting its elements into the state but not the array itself so [ ...state.messages, ...data ]
acts like a concatenation of elements in two arrays: state.messages
and data
.
Upvotes: 1