React 项目实践——创建一个聊天机器人
zhezhongyun 2025-06-15 20:37 75 浏览
作者:Fredrik Strand Oseberg
转发链接:
https://www.freecodecamp.org/news/how-to-build-a-chatbot-with-react/
前言
我的理念很简单:如果你想要在某个方面精通,那么你需要持续实践,实践一次不会有多少效果,你必须反复实践。
我在编程这件事上就是这么做的。
在这个过程中,我特别感受到:创建一些有意思的好东西是非常有趣的。你可以向朋友展示自己引以为傲的作品,坐下来敲代码实现它的过程会让你感觉欢喜。
比如说我创建了一个聊天机器人(代码)。
我们一起来创建吧!如果你想自己独立完成这个挑战,可以直接参考这份文档(其实是一个聊天机器人成品)。
好啦,我们开始吧。我就假设你已经安装了 Node,可以运行 npx 命令。如果没有的话,访问这里。
初始设置
// 运行以下代码
npx create-react-app chatbot
cd chatbot
yarn add react-chatbot-kit
yarn start
安装 npm 包,访问 localhost:3000。
然后打开 App.js,修改如下:
import Chatbot from 'react-chatbot-kit'
function App() {
return (
<div className="App">
<header className="App-header">
<Chatbot />
</header>
</div>
);
}
现在你的界面是这样的:
聊天机器人要正常工作,需要接收三个 props。首先,需要具有 initialMessages 属性,包含聊天信息对象。然后,需要有 MessageParser 用于解析,还有 ActionProvider 基于解析结果执行我们需要它执行的动作。
稍后我们进一步讲解这个。现在,在这里获取代码。
- 把 MessageParser 代码放到 MessageParser.js 文件
- 把 ActionProvider 代码放到 ActionProvider.js 文件
- 把 config 代码放到 config.js 文件
现在返回到 App.js 文件,添加以下代码:
import React from 'react';
import Chatbot from 'react-chatbot-kit'
import './App.css';
import ActionProvider from './ActionProvider';
import MessageParser from './MessageParser';
import config from './config';
function App() {
return (
<div className="App">
<header className="App-header">
<Chatbot config={config} actionProvider={ActionProvider} messageParser={MessageParser} />
</header>
</div>
);
}
localhost:3000 现在应该是这样显示:
很棒!我们已经初始化了聊天机器人,可以输入和提交一些信息了。试试看!
理解聊天机器人是怎么工作的
我们暂停一下,看看 MessageParser 和 ActionProvider 是怎么配合让聊天机器人执行动作的。
机器人初始化的时候,内部 state 的 messages 属性获取 initialMessages 属性值,将信息渲染到屏幕。
接着,当我们在聊天框输入信息,点击 submit 提交时,MessageParser(作为 props 传递给机器人调用 parse 方法。
我们进一步看看 MessageParser 的代码:
class MessageParser {
constructor(actionProvider) {
this.actionProvider = actionProvider;
}
parse(message) {
... parse logic
}
}
代码中包含 actionProvider,这跟我们传递给聊天机器人的 props ActionProvider 是一样的。我们通过这个代码解析信息,并告诉机器人执行什么动作。
比如,我们创建一个简单的响应。首先,将 MessageParser 改为:
class MessageParser {
constructor(actionProvider) {
this.actionProvider = actionProvider;
}
parse(message) {
const lowerCaseMessage = message.toLowerCase()
if (lowerCaseMessage.includes("hello")) {
this.actionProvider.greet()
}
}
}
export default MessageParser
MessageParser 接收到用户的信息,检查是否包含 “hello”。如果包含,则调用 actionProvider 的 greet 方法。
不过现在还行不通,因为我们还没有执行 greet 方法。稍后再处理这个。先处理 ActionProvider.js 文件如下:
class ActionProvider {
constructor(createChatBotMessage, setStateFunc) {
this.createChatBotMessage = createChatBotMessage;
this.setState = setStateFunc;
}
greet() {
const greetingMessage = this.createChatBotMessage("Hi, friend.")
this.updateChatbotState(greetingMessage)
}
updateChatbotState(message) {
// NOTE: This function is set in the constructor, and is passed in // from the top level Chatbot component. The setState function here // actually manipulates the top level state of the Chatbot, so it's // important that we make sure that we preserve the previous state.
this.setState(prevState => ({
...prevState, messages: [...prevState.messages, message]
}))
}
}
export default ActionProvider
现在我们在聊天框输入 “hello”,可以看到:
很好!解析信息和响应都没有问题了。我们再做一些更复杂的东西,让机器人提供我们想要的编程语言学习资料。
创建一个学习机器人
首先,回到 config.js 文件,稍作修改:
import { createChatBotMessage } from 'react-chatbot-kit';
const config = {
botName: "LearningBot",
initialMessages: [createChatBotMessage("Hi, I'm here to help. What do you want to learn?")],
customStyles: {
botMessageBox: {
backgroundColor: "#376B7E",
},
chatButton: {
backgroundColor: "#376B7E",
},
},
}
export default config
我们增加了一些属性,修改了初始信息,特别是给机器人取了个名字,更改了 messagebox 和 chatbutton 组件的颜色。
好玩的部分来了。
我们不仅可以渲染信息和回复给用户,还可以根据想要的信息来自定义 React 组件。比如,我们创建一个选择组件,引导用户做不同选择。
首先,定义学习选项组件:
// in src/components/LearningOptions/LearningOptions.jsx
import React from "react";
import "./LearningOptions.css";
const LearningOptions = (props) => {
const options = [
{ text: "Javascript", handler: () => {}, id: 1 },
{ text: "Data visualization", handler: () => {}, id: 2 },
{ text: "APIs", handler: () => {}, id: 3 },
{ text: "Security", handler: () => {}, id: 4 },
{ text: "Interview prep", handler: () => {}, id: 5 },
];
const optionsMarkup = options.map((option) => (
<button
className="learning-option-button"
key={option.id}
onClick={option.handler}
>
{option.text}
</button>
));
return <div className="learning-options-container">{optionsMarkup}</div>;
};
export default LearningOptions;
// in src/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: 1px solid green;
margin: 3px;
}
然后在机器人代码中使用组件。对 config.js 文件作如下操作:
import React from "react";
import { createChatBotMessage } from "react-chatbot-kit";
import LearningOptions from "./components/LearningOptions/LearningOptions";
const config = {
initialMessages: [
createChatBotMessage("Hi, I'm here to help. What do you want to learn?", {
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 组件设置了一些选项:
const options = [
{ text: "Javascript", handler: () => {}, id: 1 },
{ text: "Data visualization", handler: () => {}, id: 2 },
{ text: "APIs", handler: () => {}, id: 3 },
{ text: "Security", handler: () => {}, id: 4 },
{ text: "Interview prep", handler: () => {}, id: 5 },
];
暂时这些选项有一个空的 handler,我们想调用 actionProvider 替换 handler。
那么,我们想在执行这些函数的时候发生什么呢?理想状况下,机器人已经具有一些回复信息以及一个 widget 显示每个主题对应的资源列表链接。我们看看怎么实现。
首先,创建一个链接列表组件:
// in src/components/LinkList/LinkList.jsx
import React from "react";
import "./LinkList.css";
const LinkList = (props) => {
const linkMarkup = props.options.map((link) => (
<li key={link.id} className="link-list-item">
<a
href={link.url}
target="_blank"
rel="noopener noreferrer"
className="link-list-item-url"
>
{link.text}
</a>
</li>
));
return <ul className="link-list">{linkMarkup}</ul>;
};
export default LinkList;
// in src/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: 2px 2px 4px rgba(150, 149, 149, 0.4);
}
将这个组件添加到 widget 中:
import React from "react";
import { createChatBotMessage } from "react-chatbot-kit";
import LearningOptions from "./components/LearningOptions/LearningOptions";
import LinkList from "./components/LinkList/LinkList";
const config = {
...
widgets: [
{
widgetName: "learningOptions",
widgetFunc: (props) => <LearningOptions {...props} />,
},
{
widgetName: "javascriptLinks",
widgetFunc: (props) => <LinkList {...props} />,
},
],
};
export default config;
如果我们想动态给这个组件传递参数,以便对其他选项复用,那就需要给 widget 添加另一个属性:
import React from "react";
import { createChatBotMessage } from "react-chatbot-kit";
import LearningOptions from "./components/LearningOptions/LearningOptions";
import LinkList from "./components/LinkList/LinkList";
const config = {
...,
widgets: [
...,
{
widgetName: "javascriptLinks",
widgetFunc: (props) => <LinkList {...props} />,
props: {
options: [
{
text: "Introduction to JS",
url:
"https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/",
id: 1,
},
{
text: "Mozilla JS Guide",
url:
"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide",
id: 2,
},
{
text: "Frontend Masters",
url: "https://frontendmasters.com",
id: 3,
},
],
},
},
],
};
export default config;
现在,这些 props 会作为参数传递给 LinkList 组件。
我们再做两件事情。
- 给 actionProvider 添加一个方法
class ActionProvider {
constructor(createChatBotMessage, setStateFunc) {
this.createChatBotMessage = createChatBotMessage;
this.setState = setStateFunc;
}
handleJavascriptList = () => {
const message = this.createChatBotMessage(
"Fantastic, I've got the following resources for you on Javascript:",
{
widget: "javascriptLinks",
}
);
this.updateChatbotState(message);
};
updateChatbotState(message) {
// NOTICE: This function is set in the constructor, and is passed in from the top level Chatbot component. The setState function here actually manipulates the top level state of the Chatbot, so it's important that we make sure that we preserve the previous state.
this.setState((prevState) => ({
...prevState,
messages: [...prevState.messages, message],
}));
}
}
export default ActionProvider;
- 把这个方法作为 LearningOptions 组件 handler
import React from "react";
import "./LearningOptions.css";
const LearningOptions = (props) => {
const options = [
{
text: "Javascript",
handler: props.actionProvider.handleJavascriptList,
id: 1,
},
{ text: "Data visualization", handler: () => {}, id: 2 },
{ text: "APIs", handler: () => {}, id: 3 },
{ text: "Security", handler: () => {}, id: 4 },
{ text: "Interview prep", handler: () => {}, id: 5 },
];
const optionsMarkup = options.map((option) => (
<button
className="learning-option-button"
key={option.id}
onClick={option.handler}
>
{option.text}
</button>
));
return <div className="learning-options-container">{optionsMarkup}</div>;
};
export default LearningOptions;
好啦,信息量比较大。现在如果我们点击聊天机器人的 JavaScript 选项,会出现:
完美!再进一步,如果用户输入信息,机器人也应该响应。所以我们需要给 MessageParser 创建新规则。
更新 MessageParser.js 文件:
class MessageParser {
constructor(actionProvider) {
this.actionProvider = actionProvider;
}
parse(message) {
const lowerCaseMessage = message.toLowerCase();
if (lowerCaseMessage.includes("hello")) {
this.actionProvider.greet();
}
if (lowerCaseMessage.includes("javascript")) {
this.actionProvider.handleJavascriptList();
}
}
}
export default MessageParser;
在输入框键入 “javaScript”,机器人会回复同样的清单。完成啦!
欢迎在 GitHub 访问代码和文档。
结语
创建项目很有趣,也是一个帮助你拓展技能的很棒的方式。你完全可以动动脑筋,在这个项目基础上再开发别的,比如一个机器人通过一些简单的问题找到网店里最适合的产品,或者是一个帮公司回复顾客常见问题的机器人。
你可以尽量实践你的新想法。也欢迎你 pull request,帮我完善这个项目。
我觉得持续创建项目真的是开发者提升自己的唯一方式,建议你现在就动起来!
作者:Fredrik Strand Oseberg
转发链接:
https://www.freecodecamp.org/news/how-to-build-a-chatbot-with-react/
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
