将 React 应用程序与 Firebase 集成
在第 1 章Firebase 入门和 React 中,我们了解了如何将 Firebase 与 Javascript 集成,并创建了我们的第一个示例应用程序,这让我们简单了解了 Firebase 的工作原理。现在,您已经使用 Javascript 和 Firebase 完成了第一个 web 应用程序,我们将使用 React 和 Firebase 构建帮助台应用程序。
我们将首先设置 React 环境,然后快速查看 JSX 和 React 组件方法。我们还将了解如何使用 JSX 在 React 中创建表单组件,并在 Firebase 实时数据库中提交这些表单值
以下是我们将在本章中重点关注的要点列表:
React 环境设置 JSX 和 React 引导简介 使用 JSX 创建表单 Firebase 与 React 的集成 保存和读取实时数据库中的数据 建立环境
首先,我们需要创建一个类似于 Hello World 应用程序的文件夹结构,我们在第 1 章、Firebase 入门和 React 中创建了该应用程序。以下屏幕截图描述了文件夹结构:
当我们开始用 ReactJS 制作应用程序时,我们需要做一些设置,其中只涉及一个 HTML 页面和reactjs
库。创建完文件夹结构后,我们需要安装两个框架:ReactJS 和 Firebase。这就像在页面中包含 Javascript 和 CSS 文件一样简单。我们可以通过内容交付网络 (CDN )实现这一点,如谷歌或微软,但我们将在应用程序中手动获取文件,这样我们就不必依赖互联网,也可以脱机工作。
安装 React
首先,我们要去https://reactjs.org/ 并查看我们将在应用程序中使用的最新可用版本:
在写这本书时,最新版本是 v16.0.0。在本章中,我们将使用 CDN React 软件包构建我们的应用程序:
现在,打开你的浏览器,让我们看看 JSX 代码的输出:
看起来棒极了。我们可以像预期的那样看到我们的状态。
The first character should always be capitalized when you create a component in React. For example, our Add Ticket form
component is
.
对于大规模应用,不建议采用这种方法;我们不能在每次创建表单元素时将整个 JSX 代码放在一个地方。为了使我们的代码干净且易于管理,我们应该创建一个可重用的组件,并在需要使用该组件的地方提供该组件的引用。
让我们看看如何在现有代码中实现这一点,我们将创建一个可重用的文本输入组件:
const TextInput = ({ type, name, label, onChange, placeholder, value, required }) => { return ( ) }
在前面的代码段中,我们创建了一个对象,该对象接受一些与输入属性相关的参数,并将这些参数的值赋给属性的值:
type="email" name="email" label="Email" placeholder="Enter your email address" required={true}/>
现在我们只需要在我们的render
方法中添加前面的TextInput
组件,就像您在前面的代码中看到的那样,而不是在我们的应用程序中每次都添加标签和输入;这显示了 ReactJS 的威力。
使用 React 引导
React Bootstrap 是为 React 重建的开源 Javascript 框架。它类似于引导,我们已经准备好使用组件与 React 集成。React Bootstrap 不依赖于任何其他框架,因为 Bootstrap JS 依赖于 jQuery。通过使用 React 引导,我们可以确保不会有外部 Javascript 调用来呈现可能与ReactDOM.render
不兼容的组件或额外的工作。然而,我们仍然可以实现与 推特引导程序相同的功能和外观,但需要更干净、更少的代码。
让我们看看如何使用 React 引导创建Add Ticket Form
组件。
首先,按照此处提到的步骤在项目中配置 React 引导:
通过运行以下命令安装 React 引导程序 npm 包 如果您使用的是 createreact 应用程序 CLI,我们不需要担心引导 CSS;它已经存在了,我们不需要包括在内。
现在,通过使用 import 关键字,我们需要在 react 应用程序中添加 react 引导组件的引用。 例如:
从“react bootstrap/lib/Button”导入按钮; //或 从“react bootstrap”导入{Button}; 使用 React 引导添加票证表单
现在,您可能会想,既然我们已经安装了 React 引导,并且在我们的项目中通过使用import
语句添加了 React 引导的引用,那么它们是否会相互冲突?不,他们不会。React 引导与现有引导样式兼容,所以我们不需要担心任何冲突。
请看Add Ticket
组件渲染方法的代码:
Issue Type select ... Assign Department select ... Textarea />
正如您在前面的代码中所看到的,它看起来比 Twitter 引导组件更干净,因为我们可以从 React 引导导入单个组件,而不是包括整个库,例如import { Button } from 'react-bootstrap';
。
以下是受支持的表单控件列表:
现在,您可以决定是使用 React 引导还是使用带有引导样式的普通 JSX 组件。
欲了解更多详情,请查看https://react-bootstrap.github.io/components/forms/ 。
带 React 的火基
我们已经创建了一个 React 表单,您可以在该表单中将问题提交到帮助台并保存到 Firebase。为此,现在我们需要在现有应用程序中集成和初始化 Firebase。
下面是它的外观:
在 HTML 的底部添加了脚本标记:
将上一章中已有的 Firebase 配置代码复制到firebase-config.js
:
// Initialize Firebase var cOnfig= { apiKey: "", authDomain: "", databaseURL: "", projectId: "", storageBucket: "", messagingSenderId: "" }; firebase.initializeApp(config); var firebaseDb = firebase.database();
另外,将Reactjs Form
添加到react-form.js
中,以便我们的代码看起来干净且易于管理:
class AddTicketForm extends React.Component { constructor() { super(); this.handleSubmitEvent = this.handleSubmitEvent.bind(this); } handleSubmitEvent(event) { event.preventDefault(); console.log("Email--" + this.refs.email.value.trim()); console.log("Issue Type--" + this.refs.issueType.value.trim()); console.log("Department--" + this.refs.department.value.trim()); console.log("Comments--" + this.refs.comment.value.trim()); }, render() { return (); } };
道具与状态
在我们进入实践之前,我们应该知道在 React 中什么是状态,什么是道具。在 ReactJs 中,组件在 JSX 的帮助下将原始数据转换为丰富的 HTML,道具和状态与原始数据一起构建,以保持 UI 的一致性。好的,让我们确定它到底是什么:
将表单数据读写到 Firebase 实时数据库。
正如我们所知,ReactJS 组件有自己的道具和类似状态的表单,它们支持通过用户交互影响的一些道具:
和
:
| 组件 | 支撑道具 | |
和
| 值,默认值 | |
复选框或收音机的类型 | 选中,默认选中 | |
| 选中,默认值 |
In an HTML
component, the value is set via children, but it can be set by value in React. The onChange
prop is supported by all native components, such as other DOM events, and can listen to all bubble change events.
如我们所见,state 和 prop 将为您提供更改组件值和处理该组件状态的控件。
好的,现在让我们在Add Ticket form
中添加一些高级功能,可以帮助您从用户输入中获取值,在 Firebase 的帮助下,我们将这些值保存在数据库中。
Ref 属性
React 提供ref
非 DOM 属性来访问组件。ref 属性可以是回调函数,它将在安装组件后立即执行。因此,我们将在 form 元素中附加 ref 属性以获取值。
让我们在添加 REF 属性后快速查看我们的组件:
Email *
Issue Type * -- -- - Select-- -- Access Related Issue Email Related Issues Hardware Request Health & Safety Network Intranet Other
Assign Department * -- -- - Select-- -- Admin HR IT Development
Comments } > * ( 200 characters max)
Submit cancel
现在,让我们打开浏览器,看看组件的外观:
Firebase 在我们的应用程序中工作得非常好,您可以看到标题“Hello world!这是我的第一个 Javascript Firebase 应用程序”底部显示的消息;它来自 Firebase 实时数据库
此外,在控制台中,您可以在提交表单时看到这些值。
现在我们需要将这些值保存到数据库中:
//React form data object var data = { date: Date(), email:this.refs.email.value.trim(), issueType:this.refs.issueType.value.trim(), department:this.refs.department.value.trim(), comments:this.refs.comment.value.trim() }
我们对 Firebase 实时数据库的Write
数据对象执行此操作;firebase.database.Reference
是从 Firebase 检索数据的异步侦听器。此侦听器将在其初始状态和数据更改时触发一次。
We can Read
and Write
the data from Firebase Database if we have access for that, because, by default, the database is restricted and no one can access it without setting up the authentication.
firebaseDb.ref().child('helpdesk').child('tickets').push(data);
在前面的代码中,我们使用push()
方法将数据保存到 Firebase 数据库中。每次将新子级添加到指定的 Firebase 引用时,它都会生成唯一密钥。我们也可以使用set()
方法保存数据以供指定参考;它将替换该节点路径上的现有数据:
firebaseDb.ref().child('helpdesk').child('tickets').set(data);
对于Retrieve
添加数据时的更新结果,我们需要使用on()
方法连接监听器,或者在任何情况下,如果我们想要分离特定节点上的监听器,那么我们可以调用off()
方法:
firebaseDb.ref().on('child_added', function(snapshot) { var data = snapshot.val(); snapshot.forEach(function(childSnap) { console.log(childSnap.val()); this.refs.form.reset(); console.log("Ticket submitted successfully"); }); });
但是,如果我们想在没有听到变化的情况下阅读一次,我们可以使用once()
方法:
firebaseDb.ref().once('value').then(function(snapshot){ });
当我们不希望数据发生任何变化或进行任何积极的监听时,这非常有用。例如,当用户配置文件数据在我们的应用程序中成功通过认证时,在初始加载时加载该数据。
要更新数据,我们有update()
方法,要删除数据,我们只需要在数据所在的位置调用delete()
方法。
Both the update()
and set()
methods return a Promise, so we can use that to know when the write is committed to the database.
现在,让我们提交表单并在浏览器控制台中查看输出:
看起来很棒;现在,让我们来看看我们的 Firebase database:
我们可以看到我们从 ReactJS 表单提交的数据。
现在我们将以表格格式显示这些数据;为此,我们需要创建另一个 React 组件并设置组件的初始状态:
constructor(){ super(); this.state = { tickets:[] } }
现在,使用componentDidMount()
方法,我们将通过ref()
调用数据库,迭代对象,并使用this.setState()
设置组件的状态:
componentDidMount() { var itemsRef = firebaseDb.ref('/helpdesk/tickets'); console.log(itemsRef); itemsRef.on('value', (snapshot) => { let tickets = snapshot.val(); console.log(tickets); let newState = []; for (let ticket in tickets) { newState.push({ id:tickets[ticket], email:tickets[ticket].email, issueType:tickets[ticket].issueType, department:tickets[ticket].department, comments:tickets[ticket].comments, date:tickets[ticket].date }); } this.setState({ tickets: newState }); }); },
现在,我们将在 render 方法内的表中迭代票证的状态:
render() { return ( Email Issue Type Department Comments Date { this.state.tickets.map((ticket) => { return ( {ticket.email} {ticket.issueType} {ticket.department} {ticket.comments} {ticket.date} )}) }
)}
现在,每当向数据库中添加新票证时,用户都可以实时查看票证列表:
以下是我们 HTML 页面的标记:viewTickets.html
: