本文转载自:众成翻译
译者:iOSDevLog
链接:http://www.zcfy.cc/article/3813
原文:https://www.fullstackreact.com/30-days-of-react/day-16/
我们的前端应用与我们在其中显示的数据一样有趣。今天,我们开始提出数据请求,并将其集成到我们的应用中。
截至今天, 我们已经通过承诺, 使用 npm
包建立我们的应用程序, 安装我们的远程对象获取库 (whatwg-fetch
), 我们终于准备好将远程数据集成到我们的应用程序中。
获取数据
我们安装在 第14 天。fetch
库后让我们进入使用它。
为了简单起见, 让我们从昨天从 api 服务器获取当前时间的示例中进行演示:
此演示反应组件对 api 服务器发出请求, 并从它的时钟中报告当前时间。在我们添加调用来获取之前, 让我们创建一些有状态的组件, 我们将用来显示时间并更新时间请求。
代码警告墙
我们意识到, 接下来的几行是 _代码警告墙_, 我们通常试图避免, 特别是没有讨论如何工作。然而, 由于我们不是在讨论如何在这里详细地创建一个组件, 但是我们还是要填写一个完整的组件, 我们已经破例了。
如果你希望我们改变今天的做法,请留下我们的反馈 (底部的链接),。
首先, 将显示和获取当前时间的包装组件的基础如下所示。让我们复制并粘贴到我们的应用程序在src/App.js
的代码:
import React from 'react';
import 'whatwg-fetch';
import './App.css';
import TimeForm from './TimeForm';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentTime: null, msg: 'now'
}
}
// methods we'll fill in shortly
fetchCurrentTime() {}
getApiUrl() {}
handleFormSubmit(evt) {}
handleChange(newState) {}
render() {
const {currentTime, tz} = this.state;
const apiUrl = this.getApiUrl();
return (
<div>
{!currentTime &&
<button onClick={this.fetchCurrentTime.bind(this)}>
Get the current time
</button>}
{currentTime && <div>The current time is: {currentTime}</div>}
<TimeForm
onFormSubmit={this.handleFormSubmit.bind(this)}
onFormChange={this.handleChange.bind(this)}
tz={tz}
msg={'now'}
/>
<p>We'll be making a request from: <code>{apiUrl}</code></p>
</div>
)
}
}
export default App;
前面的组件是我们创建的基本状态响应组件。因为我们要显示一个表单, 我们已经包括了 TimeForm
的预期用法, 让我们创建下一个。
让我们在我们的反应应用程序中使用 create-react-app
. 来创建这个组件。将文件src/TimeForm.js
添加到我们的项目中:
touch src/TimeForm.js
现在, 让我们添加内容。我们希望我们的 TimeForm
t能够发挥作用, 允许用户在浏览器中切换时区。我们可以通过创建一个 stateful 组件来处理这个, 我们称之为 TimeForm
。我们的TimeForm
组件的外观可能如下所示:
import React from 'react'
const timezones = ['PST', 'MST', 'MDT', 'EST', 'UTC']
export class TimeForm extends React.Component {
constructor(props) {
super(props);
const {tz, msg} = this.props;
this.state = {tz, msg};
}
_handleChange(evt) {
typeof this.props.onFormChange === 'function' &&
this.props.onFormChange(this.state);
}
_changeTimezone(evt) {
const tz = evt.target.value;
this.setState({tz}, this._handleChange);
}
_changeMsg(evt) {
const msg =
encodeURIComponent(evt.target.value).replace(/%20/, '+');
this.setState({msg}, this._handleChange);
}
_handleFormSubmit(evt) {
evt.preventDefault();
typeof this.props.onFormSubmit === 'function' &&
this.props.onFormSubmit(this.state);
}
render() {
const {tz} = this.state;
return (
<form onSubmit={this._handleFormSubmit.bind(this)}>
<select
onChange={this._changeTimezone.bind(this)}
defaultValue={tz}>
{timezones.map(t => {
return (<option key={t} value={t}>{t}</option>)
})}
</select>
<input
type="text"
placeholder="A chronic string message (such as 7 hours from now)"
onChange={this._changeMsg.bind(this)}
/>
<input
type="submit"
value="Update request"
/>
</form>
)
}
}
export default TimeForm;
随着这些组件的创建, 让我们在浏览器中加载我们的应用程序后, npm start
后运行 , 我们将看到我们的形式 (虽然还没有令人难以置信的美丽)。当然, 在这一点上, 我们不会有一个正在运行的组件, 因为我们没有实现我们的数据获取。让我们现在就开始吧。
获取数据
正如我们昨天所说的, 我们将使用fetch()
api 和承诺支持。当我们调用fetch()
的方法, 它会返回我们的承诺, 在那里我们可以处理的要求, 但我们想要的。我们将向我们的 基于当前 api 服务器发出请求 (所以如果在一段时间内没有运行, 启动可能会很慢)。
我们将建立我们将请求的 url, 因为它代表了我们将在服务器上请求的时间查询。
我已经在App
组件中定义了方法 getApiUrl()
, 因此, 让我们在中填充该函数。
慢性 api 服务器接受几个变量, 我们将在表单中进行自定义。它将采取的时区与一个慢性的消息。我们将简单地开始, 并问慢性库的 pst
时区和当前时间 (now
):
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentTime: null, msg: 'now', tz: 'PST'
}
}
// ...
getApiUrl() {
const {tz, msg} = this.state;
const host = 'https://andthetimeis.com';
return host + '/' + tz + '/' + msg + '.json';
}
// ...
export default App;
现在, 当我们调用 getApiUrl()
时, 下一个请求的 url 将返回给我们。现在, 最后, 让我们实现我们的fetch()
功能。fetch()
函数接受一些可以帮助我们自定义请求的参数。最基本的fetch()
请求只需要一个 url 端点即可。fetch()
的返回值是一个承诺对象, 我们昨天深入了解过它。
让我们更新我们的fetchCurrentTime()
方法, 从远程服务器获取当前时间。我们将在响应对象上使用 .json()
方法将响应的主体从 json 对象转换为 javascript 对象, 然后通过将dateString
的响应值设置为组件状态中的currentTime
来更新我们的组件:
class App extends React.Component {
// ...
fetchCurrentTime() {
fetch(this.getApiUrl())
.then(resp => resp.json())
.then(resp => {
const currentTime = resp.dateString;
this.setState({currentTime})
})
}
// ...
}
今天我们项目的最后一部分是从窗体中获取数据, 以更新父组件。即, 当用户更新TimeForm
组件中的值时, 我们希望能够访问App
组件中的数据。TimeForm
组件已经为我们处理了这个过程, 所以我们只需要实现我们的表单功能。
当一个状态在窗体组件上发生变化时, 它将调用一个称为onFormChange
的属性。通过在App
组件中定义此方法, 我们可以访问该表单的最新版本。
事实上, 我们将只调用setState()
来跟踪表单允许用户操作的选项:
class App extends React.Component {
// ...
handleChange(newState) {
this.setState(newState);
}
// ...
}
最后, 当用户提交表单时 (按下按钮 或者 按 回车 键在输入字段中单击), 我们将希望对时间提出另一个请求。这意味着我们可以定义我们的handleFormSubmit
的属性, 只是调用 fetchCurrentTime()
方法:
class App extends React.Component {
// ...
handleFormSubmit(evt) {
this.fetchCurrentTime();
}
// ...
}
尝试运行演示和传递不同的慢速选择。真的很有趣
在任何情况下, 今天我们做了相当多的工作, 获取远程数据到我们的应用程序。然而, 在这一点上, 我们只有一页的单页应用程序。如果我们想在我们的应用程序中显示不同的页面呢?明天, 我们将开始在我们的应用程序中添加多个页面, 以便我们可以查看不同的视图。