react开发编辑器,React项目实践
react开发编辑器,React项目实践//运行以下代码 npxcreate-react-appchatbot cdchatbot yarnaddreact-chatbot-kit yarnstart 安装 npm 包,访问 localhost:3000。好啦,我们开始吧。我就假设你已经安装了 Node,可以运行 npx 命令。如果没有的话,访问这里。在这个过程中,我特别感受到:创建一些有意思的好东西是非常有趣的。你可以向朋友展示自己引以为傲的作品,坐下来敲代码实现它的过程会让你感觉欢喜。比如说我创建了一个聊天机器人(代码)。我们一起来创建吧!如果你想自己独立完成这个挑战,可以直接参考这份文档(其实是一个聊天机器人成品)。
作者:Fredrik Strand Oseberg
转发链接:https://www.freecodecamp.org/news/how-to-build-a-Chatbot-with-React/
前言我的理念很简单:如果你想要在某个方面精通,那么你需要持续实践,实践一次不会有多少效果,你必须反复实践。
我在编程这件事上就是这么做的。
在这个过程中,我特别感受到:创建一些有意思的好东西是非常有趣的。你可以向朋友展示自己引以为傲的作品,坐下来敲代码实现它的过程会让你感觉欢喜。
比如说我创建了一个聊天机器人(代码)。
我们一起来创建吧!如果你想自己独立完成这个挑战,可以直接参考这份文档(其实是一个聊天机器人成品)。
好啦,我们开始吧。我就假设你已经安装了 Node,可以运行 npx 命令。如果没有的话,访问这里。
初始设置//运行以下代码
npxcreate-react-appchatbot
cdchatbot
yarnaddreact-chatbot-kit
yarnstart
安装 npm 包,访问 localhost:3000。
然后打开 App.js,修改如下:
importChatbotfrom'react-chatbot-kit'
functionApp(){
return(
<divclassName="App">
<headerclassName="App-header">
<Chatbot/>
</header>
</div>
);
}
现在你的界面是这样的:
聊天机器人要正常工作,需要接收三个 props。首先,需要具有 initialmessages 属性,包含聊天信息对象。然后,需要有 MessageParser 用于解析,还有 ActionProvider 基于解析结果执行我们需要它执行的动作。
稍后我们进一步讲解这个。现在,在这里获取代码。
- 把 MessageParser 代码放到 MessageParser.js 文件
- 把 ActionProvider 代码放到 ActionProvider.js 文件
- 把 config 代码放到 config.js 文件
现在返回到 App.js 文件,添加以下代码:
importReactfrom'react';
importChatbotfrom'react-chatbot-kit'
import'./App.css';
importActionProviderfrom'./ActionProvider';
importMessageParserfrom'./MessageParser';
importconfigfrom'./config';
functionApp(){
return(
<divclassName="App">
<headerclassName="App-header">
<Chatbotconfig={config}actionProvider={ActionProvider}messageParser={MessageParser}/>
</header>
</div>
);
}
localhost:3000 现在应该是这样显示:
很棒!我们已经初始化了聊天机器人,可以输入和提交一些信息了。试试看!
理解聊天机器人是怎么工作的我们暂停一下,看看 MessageParser 和 ActionProvider 是怎么配合让聊天机器人执行动作的。
机器人初始化的时候,内部 state 的 messages 属性获取 initialMessages 属性值,将信息渲染到屏幕。
接着,当我们在聊天框输入信息,点击 submit 提交时,MessageParser(作为 props 传递给机器人调用 parse 方法。
我们进一步看看 MessageParser 的代码:
classMessageParser{
constructor(actionProvider){
this.actionProvider=actionProvider;
}
parse(message){
...parselogic
}
}
代码中包含 actionProvider,这跟我们传递给聊天机器人的 props ActionProvider 是一样的。我们通过这个代码解析信息,并告诉机器人执行什么动作。
比如,我们创建一个简单的响应。首先,将 MessageParser 改为:
classMessageParser{
constructor(actionProvider){
this.actionProvider=actionProvider;
}
parse(message){
constlowerCaseMessage=message.toLowerCase()
if(lowerCaseMessage.includes("hello")){
this.actionProvider.greet()
}
}
}
exportdefaultMessageParser
MessageParser 接收到用户的信息,检查是否包含 “hello”。如果包含,则调用 actionProvider 的 greet 方法。
不过现在还行不通,因为我们还没有执行 greet 方法。稍后再处理这个。先处理 ActionProvider.js 文件如下:
classActionProvider{
constructor(createChatBotMessage setStateFunc){
this.createChatBotMessage=createChatBotMessage;
this.setState=setStateFunc;
}
greet(){
constgreetingMessage=this.createChatBotMessage("Hi friend.")
this.updateChatbotState(greetingMessage)
}
updateChatbotState(message){
//NOTE:Thisfunctionissetintheconstructor andispassedin//fromthetoplevelChatbotcomponent.ThesetStatefunctionhere//actuallymanipulatesthetoplevelstateoftheChatbot soit's//importantthatwemakesurethatwepreservethepreviousstate.
this.setState(prevState=>({
...prevState messages:[...prevState.messages message]
}))
}
}
exportdefaultActionProvider
现在我们在聊天框输入 “hello”,可以看到:
很好!解析信息和响应都没有问题了。我们再做一些更复杂的东西,让机器人提供我们想要的编程语言学习资料。
创建一个学习机器人首先,回到 config.js 文件,稍作修改:
import{createChatBotMessage}from'react-chatbot-kit';
constconfig={
botName:"LearningBot"
initialMessages:[createChatBotMessage("Hi I'mheretohelp.Whatdoyouwanttolearn?")]
customStyles:{
botMessageBox:{
backgroundColor:"#376B7E"
}
chatButton:{
backgroundColor:"#376B7E"
}
}
}
exportdefaultconfig
我们增加了一些属性,修改了初始信息,特别是给机器人取了个名字,更改了 messagebox 和 chatbutton 组件的颜色。
好玩的部分来了。
我们不仅可以渲染信息和回复给用户,还可以根据想要的信息来自定义 React 组件。比如,我们创建一个选择组件,引导用户做不同选择。
首先,定义学习选项组件:
//insrc/components/LearningOptions/LearningOptions.jsx
importReactfrom"react";
import"./LearningOptions.css";
constLearningOptions=(props)=>{
constoptions=[
{text:"Javascript" handler:()=>{} id:1}
{text:"Datavisualization" handler:()=>{} id:2}
{text:"APIs" handler:()=>{} id:3}
{text:"Security" handler:()=>{} id:4}
{text:"Interviewprep" handler:()=>{} id:5}
];
constoptionsMarkup=options.map((option)=>(
<button
className="learning-option-button"
key={option.id}
onClick={option.handler}
>
{option.text}
</button>
));
return<divclassName="learning-options-container">{optionsMarkup}</div>;
};
exportdefaultLearningOptions;
//insrc/components/LearningOptions/LearningOptions.css
.learning-options-container{
display:flex;
align-items:flex-start;
flex-wrap:wrap;
}
.learning-option-button{
padding:0.5rem;
border-radius:25px;
background:transparent;
border:1pxsolidgreen;
margin:3px;
}
然后在机器人代码中使用组件。对 config.js 文件作如下操作:
importReactfrom"react";
import{createChatBotMessage}from"react-chatbot-kit";
importLearningOptionsfrom"./components/LearningOptions/LearningOptions";
constconfig={
initialMessages:[
createChatBotMessage("Hi I'mheretohelp.Whatdoyouwanttolearn?" {
widget:"learningOptions"
})
]
...
widgets:[
{
widgetName:"learningOptions"
widgetFunc:(props)=><LearningOptions{...props}/>
}
]
}
理解 Widgets
小结一下:
- 我们创建了 LearningOptions 组件
- 在 config 的 widgets 下使用组件
- 给 createChatbotMessage 函数一个选项对象,说明需要渲染哪个 widget 和信息
结果:
很棒!但是,为什么要在 config 中以 widget 的形式引入组件呢?
通过将其设置为函数,我们可以在调用时以聊天机器人的重要属性来装饰 widget。
我们定义的 widget 会接收到机器人的各种属性:
- actionProvider - 将 actionProvider 添加到 widget,以执行动作
- setState - 将 setState 添加到 widget,以操作 state
- scrollIntoView - 滑动到聊天框底部,在需要调整视图时使用这个函数
- props - 给 widget 定义的 props 将通过 configProps 传递给 widget
- state - 通过 mapStateToProps 属性将自定义 state 传递给 widget
回头想想,我们给 LearningOptions 组件设置了一些选项:
constoptions=[
{text:"Javascript" handler:()=>{} id:1}
{text:"Datavisualization" handler:()=>{} id:2}
{text:"APIs" handler:()=>{} id:3}
{text:"Security" handler:()=>{} id:4}
{text:"Interviewprep" handler:()=>{} id:5}
];
暂时这些选项有一个空的 handler,我们想调用 actionProvider 替换 handler。
那么,我们想在执行这些函数的时候发生什么呢?理想状况下,机器人已经具有一些回复信息以及一个 widget 显示每个主题对应的资源列表链接。我们看看怎么实现。
首先,创建一个链接列表组件:
//insrc/components/LinkList/LinkList.jsx
importReactfrom"react";
import"./LinkList.css";
constLinkList=(props)=>{
constlinkMarkup=props.options.map((link)=>(
<likey={link.id}className="link-list-item">
<a
href={link.url}
target="_blank"
rel="noopenernoreferrer"
className="link-list-item-url"
>
{link.text}
</a>
</li>
));
return<ulclassName="link-list">{linkMarkup}</ul>;
};
exportdefaultLinkList;
//insrc/components/LinkList/LinkList.css
.link-list{
padding:0;
}
.link-list-item{
text-align:left;
font-size:0.9rem;
}
.link-list-item-url{
text-decoration:none;
margin:6px;
display:block;
color:#1d1d1d;
background-color:#f1f1f1;
padding:8px;
border-radius:3px;
box-shadow:2px2px4pxrgba(150 149 149 0.4);
}
将这个组件添加到 widget 中:
importReactfrom"react";
import{createChatBotMessage}from"react-chatbot-kit";
importLearningOptionsfrom"./components/LearningOptions/LearningOptions";
importLinkListfrom"./components/LinkList/LinkList";
constconfig={
...
widgets:[
{
widgetName:"learningOptions"
widgetFunc:(props)=><LearningOptions{...props}/>
}
{
widgetName:"javascriptLinks"
widgetFunc:(props)=><LinkList{...props}/>
}
]
};
exportdefaultconfig;
如果我们想动态给这个组件传递参数,以便对其他选项复用,那就需要给 widget 添加另一个属性:
importReactfrom"react";
import{createChatBotMessage}from"react-chatbot-kit";
importLearningOptionsfrom"./components/LearningOptions/LearningOptions";
importLinkListfrom"./components/LinkList/LinkList";
constconfig={
...
widgets:[
...
{
widgetName:"javascriptLinks"
widgetFunc:(props)=><LinkList{...props}/>
props:{
options:[
{
text:"IntroductiontoJS"
url:
"https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/"
id:1
}
{
text:"MozillaJSGuide"
url:
"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide"
id:2
}
{
text:"FrontendMasters"
url:"https://frontendmasters.com"
id:3
}
]
}
}
]
};
exportdefaultconfig;
现在,这些 props 会作为参数传递给 LinkList 组件。
我们再做两件事情。
- 给 actionProvider 添加一个方法
classActionProvider{
constructor(createChatBotMessage setStateFunc){
this.createChatBotMessage=createChatBotMessage;
this.setState=setStateFunc;
}
handleJavascriptList=()=>{
constmessage=this.createChatBotMessage(
"Fantastic I'vegotthefollowingresourcesforyouonJavascript:"
{
widget:"javascriptLinks"
}
);
this.updateChatbotState(message);
};
updateChatbotState(message){
//NOTICE:Thisfunctionissetintheconstructor andispassedinfromthetoplevelChatbotcomponent.ThesetStatefunctionhereactuallymanipulatesthetoplevelstateoftheChatbot soit'simportantthatwemakesurethatwepreservethepreviousstate.
this.setState((prevState)=>({
...prevState
messages:[...prevState.messages message]
}));
}
}
exportdefaultActionProvider;
- 把这个方法作为 LearningOptions 组件 handler
importReactfrom"react";
import"./LearningOptions.css";
constLearningOptions=(props)=>{
constoptions=[
{
text:"Javascript"
handler:props.actionProvider.handleJavascriptList
id:1
}
{text:"Datavisualization" handler:()=>{} id:2}
{text:"APIs" handler:()=>{} id:3}
{text:"Security" handler:()=>{} id:4}
{text:"Interviewprep" handler:()=>{} id:5}
];
constoptionsMarkup=options.map((option)=>(
<button
className="learning-option-button"
key={option.id}
onClick={option.handler}
>
{option.text}
</button>
));
return<divclassName="learning-options-container">{optionsMarkup}</div>;
};
exportdefaultLearningOptions;
好啦,信息量比较大。现在如果我们点击聊天机器人的 JavaScript 选项,会出现:
完美!再进一步,如果用户输入信息,机器人也应该响应。所以我们需要给 MessageParser 创建新规则。
更新 MessageParser.js 文件:
classMessageParser{
constructor(actionProvider){
this.actionProvider=actionProvider;
}
parse(message){
constlowerCaseMessage=message.toLowerCase();
if(lowerCaseMessage.includes("hello")){
this.actionProvider.greet();
}
if(lowerCaseMessage.includes("javascript")){
this.actionProvider.handleJavascriptList();
}
}
}
exportdefaultMessageParser;
在输入框键入 “javaScript”,机器人会回复同样的清单。完成啦!
欢迎在 GitHub 访问代码和文档。
结语创建项目很有趣,也是一个帮助你拓展技能的很棒的方式。你完全可以动动脑筋,在这个项目基础上再开发别的,比如一个机器人通过一些简单的问题找到网店里最适合的产品,或者是一个帮公司回复顾客常见问题的机器人。
你可以尽量实践你的新想法。也欢迎你 pull request,帮我完善这个项目。
我觉得持续创建项目真的是开发者提升自己的唯一方式,建议你现在就动起来!
作者:Fredrik Strand Oseberg
转发链接:https://www.freecodecamp.org/news/how-to-build-a-chatbot-with-react/