介绍
我们将基于已实现的服务器,使用 ReactJS 构建一个简单的聊天应用程序。首先,我们创建静态组件,然后将它们连接到状态。最后,我们订阅事件服务器。.
先决条件
- 具备 JavaScript 和 ReactJS 的基础知识(我尽量保持简单)。
- npm v6
- npx v6
- 节点 v12
第一步:启动项目
在项目文件夹中,运行 `npx create-react-app --use-npm simple-chat-app` 命令,并等待安装完成。这将添加所有必要的依赖项,并提供简便的开发和构建体验。.
将以下文件添加到 src 文件夹:
- App.js(应该已经存在)
- ChatLineHolder.js
- ChatLine.js
- ChatInput.js
在控制台中,从项目文件夹运行 `npm run start` 命令。这将启动一个开发服务器,并在默认浏览器中打开应用程序。.
你的 src 文件夹下应该已经有一个 App.js 文件了。现在,你可以删除它返回的所有文件,只保留这一个。 <div> 退货。.
const App = () => {
return <div className='chat-app'></div>
}我们从底层向上创建组件。
步骤 2:组件
在 ChatLine.js 中,我们创建了一个具有两个属性的新组件:
姓名: 细绳信息: 细绳
这是我们稍后将从服务器接收的事件数据。.
组件一
import React from 'react'
const ChatLine = ({ name, message }) => {
return (
<li>
{name}: {message}
</li>
)
}
export default注意:ReactJS 会自动阻止 html 注入,所以您无需担心。.
步骤 3:组件
在 ChatHolder.js 中,我们创建了一个只接受一个基本组件的新组件:
行:Array<{ name: string, message: string }>
如果 线条 如果为空,则显示简单的通知。.
if (lines.length === 0) {
return <div>Chat history is empty</div>
}Lines 是一个对象数组。每个对象都有一个 name 属性和一个 message 属性。我们遍历数组中的所有元素,并将 name 和 message 这两个属性传递给组件,从而获得结果。让我们创建多个 ChatLine 节点。.
const chatLines = lines.map(
(line, index) => (
<ChatLine key={index} name={line.name} message={line.message} />
)
)然后结果是
- 渲染完成后,我们得到最终的组件:
- onSend: (message: string) => void
- 名称:正在聊天的用户的名称。
- chatLines:表示聊天记录的数组。
- eventLister:用于管理来自服务器的事件。(注:我决定将监听器放在这部分。).
- 向服务器发送消息
- 订阅服务器发送的事件
import React from 'react'
import ChatLine from './ChatLine'
const ChatLineHolder = ({ lines }) => {
if (lines.length === 0) {
return <div>Chat history is empty</div>
}
const chatLines = lines.map(
(line, index) => (
<ChatLine key={index} message={line.message} name={line.name} />
)
)
return (
<ul>
{chatLines}
</ul>
)
}
export default ChatLineHolder注意:通常情况下,你会使用唯一标识符作为键。在这种情况下,我们可以安全地使用索引,因为索引和对象之间的关联不会改变。但在实际应用中,这会非常令人沮丧。.
步骤 4:组件
您可能已经注意到,目前仍然无法导入邮件。处理文本输入,并在提交时使用回调函数,以便在按钮点击时启动新的聊天消息。需要一个属性:
用户输入组件维护其状态并管理更新。.
const [value, setValue] = useState('')
const onChange = (event) => {
setValue(event.target.value)
}当点击提交按钮时,会调用 onSend 函数并传入当前状态。由于我们不希望用户手动清除输入框,因此在调用 onSend 后会重置状态。.
const onClickSend = () => {
onSend(value)
setValue('')
}
这是最后一个组成部分:
import React, { useState } from 'react'
const ChatInput = ({ onSend }) => {
const [value, setValue] = useState('')
const onChange = (event) => {
setValue(event.target.value)
}
const onClickSend = () => {
setValue('')
onSend(value)
}
return (
<div>
<input type='text' value={value} onChange={onChange} />
<button onClick={onClickSend}>send</button>
</div>
)
}
export default ChatInput步骤 5:组件
模式
由于我们的组件不存储任何数据,作为我们用于管理状态的主要组件,我们有 3 种类型的状态:
(为了简单起见,在实际应用中您可能需要采取不同的方法。)
我们使用状态钩子来初始化状态:
const [chatLines, setChatLines] = useState([])
const [eventListener, setEventListener] = useState(null)
const [name] = useState(generateRandomName())组件渲染测试
目前我们只显示我们的名称和组件。我们展示的聊天队列包含固定的项目。由于聊天队列是一个空数组,因此需要发出通知。我们调用一个空的 flash 函数来触发通知。我们会发送。执行将在下一步进行。.
return (
<div className='chat-app'>
<h2>Chatting as {name}</h2>
<ChatLineHolder lines={chatLines} />
<ChatInput onSend={() => {}} />
</div>
)如果你想检查你的实现是否适用于某些数据,只需向 chatLines 添加一些项目即可。.
const [chatLines, setChatLines] = useState([{ name: 'Thomas', 'message': 'Hi' }])
添加互动
我们已经可以在聊天输入框中输入文本,但是按下发送键没有任何反应。这是因为我们有一个叫做……的函数。我们发送的那个程序完全没有任何作用。所以我们需要一个实现方案。.
由于我们尚未连接到服务器,我们将以一种直接更新状态的方式来实现 onSend 事件。为此,我们将添加一个辅助函数 addChatLine: (chatLine) => void。稍后我们将使用它来处理服务器发送的消息事件。.
const addChatLine = (chatLine) => {
setChatLines(chatLines => {
return [...chatLines, chatLine]
})
// If you don't have a lot of experience with ReactJS, just think of this as:
// setChatLines([...chatLines, chatLine])
}onSend 会创建一个聊天线路对象并调用 addChatLine 方法。
const onSend = (message) => {
const chatLine = { name, message }
addChatLine(chatLine)
}别忘了发送给发送。.
return (
<div className='chat-app'>
<h2>Chatting as {name}</h2>
<ChatLineHolder lines={chatLines} />
<ChatInput onSend={onSend} />
</div>
)现在您应该可以在输入框中输入文本,点击发送,并立即看到您的消息。.
步骤六:连接到服务器
自言自语很无聊。所以我们需要将应用程序连接到服务器。这个过程分为两个部分:
向服务器发送消息
我们需要修改之前编写的 onSend 函数。我们可以用一个简单的 fetch 请求替换整个请求体,该请求体会发送我们的名字和消息。重要的是不要调用 addChatLine 函数,因为我们稍后会在收到服务器发送的事件后调用它。.
const onSend = async (message) => {
fetch('http://localhost:4000/say',
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
method: 'post',
mode: 'no-cors',
body: `name=${name}&message=${message}`
})
}如果您现在点击提交按钮,系统会向服务器发送请求,但您的状态暂时不会更新!我们将在下一步中解决这个问题。.
订阅服务器发送的事件
在开始监听事件之前,我们需要一个处理此类消息事件的函数。由于我们稍后会连接到消息类型的事件,因此可以相应地实现它。该函数的作用是接收 event.data,将其解析为一个对象,然后调用 addChatLine 函数。.
const onMessage = (event) => {
const chatLine = JSON.parse(event.data)
addChatLine(chatLine)
}
为了接收服务器发送的事件,我们使用本地地址创建一个 EventSource 类的对象。然后,我们为该消息类型添加一个事件监听器。接着,我们将其包装在一个 useEffect hook 中(这确保当组件……时)。它挂载后,事件源会被初始化,然后挂载完成后就会关闭。.
useEffect(() => {
let source = new EventSource('http://localhost:4000/listen')
source.addEventListener('message', onMessage)
setEventSource(source)
return () => { source.close() }
}, [])成分最终效果如下:
import React, { useEffect, useState } from 'react'
import ChatLineHolder from './ChatLineHolder'
import ChatInput from './ChatInput'
const App = () => {
const [chatLines, setChatLines] = useState([])
const [eventSource, setEventSource] = useState(null)
const [name] = useState(generateRandomName())
const addChatLine = (chatLine) => {
setChatLines(chatLines => [...chatLines, chatLine])
}
const onMessage = (event) => {
const chatLine = JSON.parse(event.data)
addChatLine(chatLine)
}
useEffect(() => {
let source = new EventSource("http://localhost:4000/listen")
source.addEventListener('message', onMessage)
setEventSource(source)
return () => { source.close() }
}, [])
const onSend = (message) => {
fetch(
`http://localhost:4000/say`,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
method: "post",
mode: 'no-cors',
body: `name=${name}&message=${message}`,
})
}
return (
<div className='chat-app'>
<h2>Chatting as {name}</h2>
<ChatLineHolder lines={chatLines} />
<ChatInput onSend={onSend} />
</div>
)
}
export default App结果
现在你可以用两个标签页打开页面,同时和两个不同的身份聊天!你还可以挂载两次 App 组件(通过修改 index.js 文件),因为每个实例都有自己的状态。.









