我正在尝试仅使用 React js 和 Django 构建聊天应用程序。当我在输入中键入消息并点击发送时,它会获取输入并将其发送到 API,API 返回消息并使用 useEffect 呈现它,接下来如果我收到回复,我也想呈现它,问题是:-
1) 当我点击发送时,我收到内部服务器错误状态 500,但我将消息发送到的号码正在接收消息,这意味着正在发送消息。 2)当useEffect在发送消息后运行时,它不断地开始运行并且不会停止。 3) 我只收到传递的消息,而不是从 api 收到的消息。
请帮我解决这些问题。 聊天组件:
import React, { useEffect, useState } from 'react'
import ArchiveOutlinedIcon from '@material-ui/icons/ArchiveOutlined';
import './chat.css'
import { IconButton } from '@material-ui/core';
import AddIcon from '@material-ui/icons/Add';
//ICONS
import SendIcon from '@material-ui/icons/Send';
import NoteIcon from '@material-ui/icons/Note';
import { Link, useParams } from 'react-router-dom';
import axios from 'axios';
interface ParamTypes {
userId: string
}
const ChatBox = () => {
const { userId } = useParams<ParamTypes>()
const [messages, setMessages] = useState<any[]>([])
const [formInput, setFormInput] = useState<any>({
to: '',
body: ''
})
//FETCHING SMS LIST WHEN RENDERED 2)RE-RENDER WHENuserId changes
useEffect(() => {
//GET SMS LIST FROM BACKEND
const getData = async () => {
console.log('Room Id', userId);
return await axios.get(`http://206.189.138.105/api/sms/v1/list-sms/${userId}/`)
.then((response) => {
setMessages(response.data)
console.log('list sms', response.data)
// console.log('list response', response)
}).catch((err) => console.log(err)
)
}
getData()
return () => {
getData()
}
}, [userId])
//HANDLE FORM INPUT CHANGES
const handleChange = (name: any) => (event: any) => {
setFormInput({
...formInput,
to: userId,
[name]: event.target.value
})
}
const getFormData = (object: any) => {
const formData = new FormData();
Object.keys(object).forEach(key => formData.append(key, object[key]));
return formData;
}
//SENDMESSAGE
const sendMessages = async (event: any) => {
event.preventDefault()
console.log('send-clicked', formInput);
await axios.post('http://206.189.138.105/api/sms/v1/send-sms', getFormData(formInput))
.then((response) => {
setMessages(response.data)
setFormInput({})
console.log('addnewmsgInputs', response.data)
}).catch((err) => console.log(err)
)
}
return (
<div className="chat">
{/* //HEADER */}
<div className="chat__header">
<div className="chat__header__left">
<h4>ivory 811-01-100</h4>
<p style={{ color: 'grey', fontWeight: 500, fontSize: '14px' }}>Toch cost valley</p>
</div>
<div className="chat__header__right">
<Link style={{ display: 'flex' }} to="/archived">
<ArchiveOutlinedIcon style={{ color: 'grey', marginRight: '5px' }} fontSize="small" /> <p style={{ color: 'grey', fontSize: '14px', fontWeight: 500, margin: 0 }}>
Archive
</p>
</Link>
</div>
</div>
{/* //CHATMESSEGES */}
{/* MAP&LIST THE ROOMS MESSAGES */}
<div className="chat__box">
{messages.map((message, i) => (
<div key={i} className="chat__boxMsg">
<p className={`chat__message ${message.status === "received" && 'chat__reciever'}`} >
<span className={message.status === "delivered" ? "chat__name" : "chat__name--reciver"}> {message.from_number}</span>
{message.body}
</p>
<span className={message.status === "received" ? 'chat__timeStamp' : 'chat__timeStamp__reciver'}>12 sta </span>
</div>
))}
</div>
{/* //SENDBTNS%INPUT */}
<form onSubmit={sendMessages} className="chat__box__send">
<textarea onChange={handleChange('body')} className="chat_textarea" placeholder="Type..." />
<div className="chat__box__sendBtnSection">
<div className="chat__box__template">
<input
accept="image/*"
style={{ display: 'none' }}
id="contained-button-file"
multiple
type="file"
/>
<label style={{ display: 'flex' }} htmlFor="contained-button-file">
<AddIcon style={{ color: '#3f51b5' }} fontSize="small" />
<p>Template</p>
</label>
</div>
<div className="chat__box__icons">
<input style={{ display: 'none' }} id="icon-button-file" type="file" />
<label htmlFor="icon-button-file">
<IconButton color="primary" aria-label="upload picture" component="span">
<NoteIcon fontSize="small" />
</IconButton>
</label>
<button className="chat__sendbtn" type="submit">
<SendIcon style={{ marginRight: '3px' }} fontSize="small" /> Send
</button>
</div>
</div>
</form>
</div >
)
}
export default ChatBox
侧边栏组件:
import React, { useState, useEffect } from 'react'
import { createStyles, makeStyles, Theme, Button, TextField } from '@material-ui/core';
import CreateOutlinedIcon from '@material-ui/icons/CreateOutlined';
import SearchIcon from '@material-ui/icons/Search';
import Modal from '@material-ui/core/Modal';
import Backdrop from '@material-ui/core/Backdrop';
import Fade from '@material-ui/core/Fade';
import CloseIcon from '@material-ui/icons/Close';
import SendIcon from '@material-ui/icons/Send';
import './Sidebar.css'
import SidebarChat from './SidebarChat/SidebarChat'
import axios from 'axios'
const Sidebar = () => {
//style func material-ui
const classes = useStyles()
//all the states to handle ui beahvious
const [open, setOpen] = useState(false);
const [searchTerm, setSearchTerm] = useState('');
const [usersMessages, setUsersMessages] = useState<any[]>([]);
const [usersList, setUsersLists] = useState<any[]>([]);
// const [loading, setLoading] = useState(false);
const [formInput, setFormInput] = useState<any>({
to: '',
body: ''
})
//destructure formData state
const { to, body } = formInput;
//POPULATES userLists state
const getUsers = async () => {
await axios.get(`http://206.189.138.105/api/sms/v1/sms-users`)
.then((response) => {
setUsersLists(response.data)
// console.log(response.data)
}).catch((err) => console.log(err)
)
}
//FETCHING USER LIST ON FIRST RENDER & WHEN userList state changes it re-renders
useEffect(() => {
getUsers()
}, [])
//POPULATES userMessages state
const getSms = async () => {
await axios.get(`http://206.189.138.105/api/sms/v1/list-sms/+610466993589/`)
.then((response) => {
setUsersMessages(response.data)
console.log(response.data)
}).catch((err) => console.log(err)
)
}
//FETCHING MESSAGES LIST ON FIRST RENDER & WHEN userList state changes it re-renders
useEffect(() => {
getSms()
}, [])
//HANDLE FORM INPUT CHANGES
const handleChange = (name: any) => (event: any) => {
setFormInput({
...formInput,
[name]: event.target.value
})
}
//CONVERT MESSAGE INPUT INTO FORM DATA TO SEND IN THE BAkCEND
function getFormData(object: any) {
const formData = new FormData();
Object.keys(object).forEach(key => formData.append(key, object[key]));
return formData;
}
//HANDLES FORM SUBMIT
const handleSubmit = async (event: any) => {
event.preventDefault()
console.log('addnewmessage--clicked', getFormData(formInput));
await axios.post('http://206.189.138.105/api/sms/v1/send-sms', getFormData(formInput))
.then((response) => {
setUsersMessages(response.data)
console.log('addnewmsgInputs', response.data)
}).catch((err) => console.log(err)
)
}
// if (loading) {
// return (<h4>users loading...</h4>)
// }
//PREVENTS DEFUALT BEHAVIOUR LIKE LOADING
const handleSearch = (event: any) => {
event.preventDefault()
// console.log('event');
}
//filters searched results
const filteredUsers = usersMessages.filter(user => {
return user.from_number.toLowerCase().includes(searchTerm.toLowerCase())
})
//MODAL OPEN AND CLOSE
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<>
<div className="sidebar">
{/* HEADER */}
<div className="sidebar__header">
<div onClick={handleOpen} className="sidebar__header__newMsg" >
<CreateOutlinedIcon style={{ color: "#4fab4a" }} fontSize="small" /> <h4 style={{ color: "#4fab4a" }} >New Message</h4>
</div>
{/* INPUT+SEARCH */}
<div onSubmit={handleSearch} className="search">
<form className="searchform" >
<input className={classes.input} type="text" value={searchTerm} onChange={(event) => setSearchTerm(event.target.value)} />
<SearchIcon fontSize="small" style={{ color: '#2167b9' }} />
</form>
</div>
</div>
{/* CHATS */}
{/* map through searched resulst & displays it */}
<div className={classes.sidebar__userList}>
{filteredUsers.map((item, i) => (
<SidebarChat key={i} item={item} />
))}
</div>
</div>
{/* MODAL TO GET DATA FOR NEW MESSAGE */}
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
className={classes.modal}
open={open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<div className={classes.paper}>
<div className={classes.close}>
<CloseIcon onClick={handleClose} />
</div>
<form onSubmit={handleSubmit} >
<h2 id="transition-modal-title">SEND MESSAGES</h2>
{/* <Input className="msginput" type="text" placeholder="Your Name.." /> */}
<input type="text" required value={to} onChange={handleChange('to')} className="msginput" placeholder="Your Number.." />
<TextField type="text" required value={body} onChange={handleChange('body')} variant="outlined" multiline placeholder="Your Message..." rows="5" fullWidth />
<div style={{ marginTop: '2rem' }}>
<Button variant="outlined" className="modal__btn" color='primary' type="submit"> <SendIcon style={{ marginRight: '3px' }} fontSize="small" />Send</Button>
</div>
</form>
</div>
</Fade>
</Modal>
</>
)
}
export default Sidebar
//CSS FOR MATERIAL UI COMPONENTS
const useStyles = makeStyles((theme: Theme) =>
createStyles({
sidebar__header__right: {
'&>*': {
marginLeft: '1rem'
}
},
sidebar__userList: {
flex: '1',
overflowY: 'scroll'
},
modal: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center',
},
paper: {
backgroundColor: theme.palette.background.paper,
boxShadow: theme.shadows[5],
padding: theme.spacing(2, 4, 3),
width: '400px'
},
close: {
display: 'flex',
justifyContent: 'flex-end',
},
input: {
border: 'none',
width: '100%',
height: '100%',
borderRadious: '50px',
fontSize: '18px',
color: 'grey',
fontWeight: 500,
}
}),
);