用React实现小Q聊天机器人
前几篇讲过用Vue实现小Q聊天机器人,既然用了Vue,那React自然也是少不了的,本项目实现效果与vue实现的效果完全一样:
GitHub源码:https://github.com/baiyuliang/Qrobot_React
进入正题之前,我们来聊聊前端三剑客 angular,react,vue!
这三种框架的面世时间:angular>react>vue,angular出世这么早,但是为什么我们在国内常见的前端开发基本都是用的react或者vue呢?主要是angular的版本升级出现了断层,也就是新版本不兼容老版本,导致流失大量用户,另外angular框架量级比较重,直白点就是难用!就国内的互联网环境来看,这注定是流行不起来的!所以react成为了最流行的前端开发框架,而新出世的vue凭借着它的易用性也迅速成为了最火的前端开发框架!
据本人了解,就国内目前最火的几种前端或者跨端开发平台,基本都是基于react和vue这两种框架,例如:
1.weex基于vue(现在通过rax也间接支持react)
2.rn不必说了,基于react
3.taro 支持react和vue
4.uni-app 基于vue
可以说学习前端,除了最基础的js+html+css外,react和vue是必学框架,没商量!
回到本项目,接下来,我会基于本项目粗略的对react和vue的实现过程进行一个对比,但不会深入!
1.创建项目
本人较懒,不喜欢用命令行去创建项目再外加一堆配置,而是直接用WebStrom创建,跟前几篇vue创建项目一样:
创建完成即可运行!
2.项目结构
我这里进行一个完整项目对比:左vue,右react
3.页面结构、组件
vue的页面都是以.vue结尾的文件格式,其中包含了 templete,script,style,模板(html布局),js操作,css样式全在一个文件中实现,并且style提供scope属性,来确保css样式不会冲突,而vue创建组件同样也是创建.vue后缀文件,并声明组件名称name:XXX;
react的页面,没有特殊格式,全部为js,在这里大家有必要先了解一下JSX
react组件形式有两种:class组件和函数(function)组件,
class组件功能大而全,类似于Java的类,可以继承,有构造方法,静态方法,普通方法等,通过render()函数渲染DOM树,通过export default导出组件:
import React from 'react'
class Page2 extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
page2
</div>
)
}
}
export default Page2
函数组件功能比较单一,return jsx格式DOM树即可!
function Item() {
return <div>Item</div>
}
react相当于将js,html糅合到了一块,而css则单独分离了出去,所以使用样式时必须创建对应的css文件,并通过import导入!但是需要注意的是,react并没有像vue一样提供scope,所以直接通过
import ‘xxx.css’
使用会导致样式冲突,解决办法有两个:一个是给class名加上前缀来保证类名唯一性,另一个是css模块化:
import Style from ‘xxx.css’
<div className={Style.xxx}></div>
4.数据绑定
vue:通过v-model进行双向数据绑定;
react:单项数据绑定,只能通过state进行数据同步!
关于双向数据绑定好,还是单项数据绑定好,vue和react都有自己的解释,开发者也都有自己的理解,不用纠结于此!
5.网络请求
网络请求部分,两者倒没有什么不同,vue版小Q使用axios进行网络请求封装,而react可以直接拿来使用就可以了,没有任何区别!
6.跨域问题
vue在使用代理解决跨域时的方法,配置vue.config.js:
module.exports = {
devServer: {
proxy: {
"/api": {
target: 'https://api.ai.qq.com',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
}
}
};
react则配置setupProxy.js(注意文件放入位置):
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
createProxyMiddleware('/api', { //`api`是需要转发的请求
target: 'https://api.ai.qq.com', // 这里是接口服务器地址
changeOrigin: true,
})
)
}
当然,两者还有其它很多不同的地方,就不再一一列举了,这里贴出聊天主界面代码,完整代码可以去GitHub(Qrobot_React)下载:
import React from "react";
import {getChatResponse} from "../api/ApiChat";
import './Chat.scss'
import RightItem from "../components/RightItem";
import LeftItem from "../components/LeftItem";
class Chat extends React.Component {
constructor(props) {
super(props);
this.state = {
text: '',
msglist: [{
id: 1,
type: 1,
content: '欢迎你!',
me: false
}]
}
}
//调用接口
getResponse = (text) => {
getChatResponse(text).then(res => {
this.state.msglist.push({
id: this.state.msglist[this.state.msglist.length - 1].id + 1,
type: 1,
content: res.data.answer,
me: false
})
this.setState({
msglist: this.state.msglist,
})
})
}
//输入框数据改变时同步state
changeText = (e) => {
this.setState({
text: e.target.value
})
}
//监听enter键
onKeyup = (e) => {
if (e.keyCode === 13) {
this.send()
}
}
//发送文本
send = () => {
if (this.state.text) {
this.state.msglist.push({
id: this.state.msglist[this.state.msglist.length - 1].id + 1,
type: 1,
content: this.state.text,
me: true
})
this.setState({
msglist: this.state.msglist,
text: ''
})
this.getResponse(this.state.text)
}
}
//自动滚动到底部
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({behavior: "smooth"});
}
//数据更新时执行scrollToBottom
componentDidUpdate() {
this.scrollToBottom();
}
render() {
return (
<div className="chat-container">
<div className="chat-list">
<ul>
<ListItem list={this.state.msglist}/>
</ul>
<div style={{float: "left", clear: "both"}}
ref={(el) => {
this.messagesEnd = el;
}}>
</div>
</div>
<div className="chat-bottom">
<div className="chat-line"/>
<div className="chat-input-send">
<input placeholder="请输入内容..." value={this.state.text} onChange={this.changeText}
className="chat-input" onKeyUp={this.onKeyup}/>
<button className="chat-send" onClick={this.send}>发送</button>
</div>
</div>
</div>
)
}
}
function ListItem(props) {
return props.list.map(item => {
if (item.me) {
return <li key={item.id}><RightItem msg={item}/></li>
} else {
return <li key={item.id}><LeftItem msg={item}/></li>
}
})
}
export default Chat
如果看过本人vue实现小Q文章的同学,会知道如何在vue中解决聊天列表自动滚动到底部的问题,而react依然面临着这个问题,解决办法其实大同小异,都是在列表下方放置一个空的div,并在每次聊天结束后,定位到这个div的位置:
第一步:
<div className="chat-list">
<ul>
<ListItem list={this.state.msglist}/>
</ul>
<div style={{float: "left", clear: "both"}}
ref={(el) => {
this.messagesEnd = el;
}}>
</div>
</div>
第二步:
//自动滚动到底部
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({behavior: "smooth"});
}
//数据更新时执行scrollToBottom
componentDidUpdate() {
this.scrollToBottom();
}
上一篇: Token原理以及应用