65.9K
CodeProject 正在变化。 阅读更多。
Home

如何使用模拟联系人 API 构建 React 应用

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2018年1月8日

CPOL

6分钟阅读

viewsIcon

18644

本教程将教您如何从头开始构建一个 React 应用程序。此外,我们将使用 React 的 fetch API 向模拟服务器发出异步请求。

React 是一种流行的前端 JavaScript 技术,用于创建交互式用户界面。您可以使用 React 库构建一个健壮且现代的 Web/移动应用程序,而无需过多考虑后端。您可以构建任何东西,从待办事项列表应用程序到像 Facebook 这样庞大的应用程序。今天,我将带您完成构建联系人应用程序前端的步骤。该应用程序将连接到 contacts API 端点作为后端。本教程还应帮助您开始在 React 中使用 Fetch API。

概述和先决条件

在本教程中,我们将介绍两件事。

  1. 如何创建 React 应用程序?
  2. 如何使前端和 API 端点对接?

第二点是 React 教程中很少涉及的内容。我们将通过创建一个从联系人 API 服务器检索数据的基本应用程序来弥补这一不足。出于演示目的,我将使用一个模拟 API 服务。但是,您可以通过使用实际的联系人 API(如 Google APILusha 的联系人 API 等)使您的应用程序具有实际用途。它们也是免费且实用的。

本教程的代码可在我的 Github 存储库 中找到。我还通过 codesandbox 设置了实时演示。

create-react-app 是我首选的从头开始创建 React 应用程序的工具。如果尚未安装,请安装 create-react-app

npm install create-react-app

现在,按照以下方式创建一个新项目

create-react-app contact-list

使用 yarn start 启动服务器。

应用程序结构

这就是我们希望应用程序看起来的样子。顶部有一个搜索栏,联系人列表占据屏幕的其余部分。我将使用 Bootstrap 和 Font Awesome 图标进行样式设置。

An image of the contact list application

这就是我希望我们的应用程序的工作方式。最初,视图将从服务器检索所有联系人并显示它们。然后,您可以使用搜索栏按姓名或电话号码搜索联系人。

我们可以将整个结构分解为三个组件,其中两个是可重用的——App 组件、SearchBar 组件和 ContactCard 组件。
以下是 App 组件的外观

class App extends Component {
.
.
render() {
return(
    <div className="row">
      <div className="col-xs-12 col-sm-offset-3 col-sm-6">
        <span className="title">Contacts</span>
          <SearchBar />
    <ul cl assName="list-group" id="contact-list">
         <li className="list-group-item"> 
           <ContactCard />
         </li>
        </ul>
     </div>
   </div>
  )
}

从联系人 API 检索联系人

让我们添加一些状态。我们已经初始化了 state 对象,其中包含 searchTextsearchResultcontactList

constructor(props) {
    super(props);
    this.state = {
      searchText: '',
      searchResult: [],
      contactList: []
    }

接下来,我们将从服务器检索所有联系人。我已经在 mockable.io 上设置了一个模拟 API 来模拟真实的联系人 API。当发出 GET 请求时,API 会返回以下 JSON。您可以自己尝试。

{ "code": 200,
  "contacts":[
  {
    "name": "Mark",
    "surname": "Cook",
    "gender": "male",
    "address": "52 East Forest Rd. mRockford, MI 49341",
    "age": 27,
    "title": "mr",
    "phone": "(396) 881 3396",
    "birthday": {
      "dmy": "09/08/1990",
      "mdy": "08/09/1990",
      "raw": 650246246
    },
  }, 
 ...
 ]
}

由于我们需要在组件首次挂载时检索联系人,因此我将使用 componentWillMount 生命周期方法。首先,创建一个保存 contacts API 的常量。

const contactsAPI = 'https://demo1443058.mockable.io/codeproject_tutorial/api/contacts';

现在,定义 componentWillMount() 方法如下

componentWillMount() {
    let init = {
         method: 'GET',
         headers: new Headers(),
         mode: 'cors',
         cache: 'default' 
      };

    fetch(contactsAPI, init)
      .then( response => response.json())
      .then( 
        data => this.setState( 
          prevState => ({
          contactList: [...data.contacts]
          }) 
      )
    )
}

fetch() 方法接受两个参数,API URL 和一个可选对象,您可以使用该对象来定义某些附加属性。fetch() 返回一个 Promise,您可以像这里一样链接多个 Promise。我们首先将其转换为 JSON 对象,然后将获取的数据移动到状态中,以便我们可以在 render 方法中使用它。

显示联系人数据

我们已经确保数据已从 contacts API 获取并存储在 App 组件挂载时存储的状态中。现在,我们需要将数据传递给 Contactcard 组件。

 <ul className="list-group" id="contact-list">
            { this.state.contactList().map(
                (contact) => 
                  <li key={contact.email} className="list-group-item"> 
                    <ContactCard contact = {contact}/>
                  </li>
              )
            }
 </ul>

联系人信息可在 props.contacts 中找到。您可以像我在下面那样解构 props,使代码更具可读性。正在显示存储在 contact.namecontact.surnamecontact.phonecontact.emailcontact.address 中的数据。我使用了一些额外的 CSS 样式和 HTML 来使联系人卡片看起来不错。

  const ContactCard = ({contact}) => {
    return(
       <div>
            <div className="col-xs-4 col-sm-3">
                <img src={contact.photo} alt={contact.name + ' ' + contact.surname} 
                                         className="img-responsive img-circle" />
            </div>
            <div className="col-xs-8 col-sm-9">
                <span>{contact.name + ' ' + contact.surname}</span><br/>
                
                <span title={contact.address}></span>
                <span>{contact.address}</span><br/>
                
                <span title={contact.phone}></span>
                <span>{contact.phone}</span><br/>
                
                <span title={contact.email}></span>
                <span>{contact.email}</span><br/>
            </div>
            <div className="clearfix"></div>
       </div>        
    )
}

搜索联系人列表

对于搜索联系人,我们已经有了一个 SearchBar 组件。以下是搜索功能应如何实现的概述

  1. SearchBar 组件托管搜索栏的 UI,其中包括一个输入控件字段。
  2. 当输入字段更改时,会触发 onChange 事件。
  3. onChange 事件会执行父组件的回调,并将输入控件的值作为参数传递。
  4. 父组件,在我们的例子中是 App 组件,有一个 handleSearch 方法。
const SearchBar = ({onSearch}) => {
    const handleChange = (e) => {
        onSearch(e.target.value);
    }
    return( 
        <div className="input-group ">
            <input onChange = {handleChange} className="form-control" 
             type="search" placeholder="Search for a contact" id="example-search-input" />
            <button className="btn btn-default" type="button">
                <i className="fa fa-search"></i>
            </button>
        </div>
    )
}

这是回调的 props。

<SearchBar onSearch={this.handleSearch} />

对于搜索逻辑,您可以通过多种方式来处理。以下是我认为最容易实现的一种。

  • 清除 searchResult 数组的状态,以便以前的搜索结果不会显示出来。
  • 联系人列表中的每个联系人都会使用 map 方法进行映射,并与 searchText 一起作为参数传递给 searchContact 函数。
  • searchContact 函数检查联系人的 nameemailphone 属性是否与 searchText 匹配。
  • JavaScript 的 String.prototype.search() 用于比较 string,如果找到匹配项,则返回 -1
  • 如果找到匹配的联系人,则将其存储在状态中。

这是 handleSearch() 的代码以及搜索单个联系人的逻辑。

 handleSearch(searchText) {
   
    this.setState({searchResult: [], searchText: searchText});
    this.state.contactList.map(contact => {
    
    if(searchContact(contact, searchText)) {
         this.setState( prevState => ({
           searchResult: [...prevState.searchResult, contact]
         }), () => console.log(this.state.searchResult))
      }
    })
  }
...
/* searchContact function */
 const searchContact = (contact, searchText) => ( 
     contact.name.toLowerCase().search(searchText.toLowerCase()) != -1 || 
     contact.surname.toLowerCase().search(searchText.toLowerCase()) != -1 || 
     contact.phone.toString().search(searchText) != -1 
 )

查询联系人 API 以获取搜索词

或者,您可能希望在每次按键或按下提交按钮后直接查询 API 以获取搜索词。这更耗费资源,但如果 contacts API 类似于云中的电话簿,这里有一些您可以做的事情。我鼓励您自己尝试这部分。

  1. 清除 searchResult 的状态,就像我们之前做的那样。
  2. 使用 fetch,向服务器发送一个 GET 请求,并将 searchText 追加到如下所示。
  3. GET https://api.example.com/person?firstName=`${searchText}`
  4. 将响应存储在 this.state.searchResult

如果您需要搜索姓氏和电话号码,您可能需要发出多个 API 调用并将结果追加到状态中。

我们差不多完成了联系人应用程序。但是,搜索结果尚未显示在屏幕上。这是因为我们还没有将 searchResult 提供给 ContactCard 组件。我们可以这样做

<ul className="list-group" id="contact-list">
            { this.state.searchResult().map(
                (contact) => 
                  <li key={contact.email} className="list-group-item"> 
                    <ContactCard contact = {contact}/>
                  </li>
              )
            }
</ul>

但是,当组件挂载时,组件不会从服务器获取联系人。要解决此问题,请创建一个新方法或使用三元运算符来执行以下操作

returnContactList() {
   return this.state.searchText ? this.state.searchResult :this.state.contactList
  }

并让 returnContactlist() 决定返回哪个列表。这是代码的最终版本。

<ul className="list-group" id="contact-list">
            { this.returnContactList().map(
                (contact) => 
                  <li key={contact.email} className="list-group-item"> 
                    <ContactCard contact = {contact}/>
                  </li>
              )
            }
</ul>

瞧!我们已经用 React 构建了我们自己的工作联系人应用程序。

摘要

我们从零开始在大约 30 分钟内构建了一个联系人列表应用程序。这本身就是一项了不起的成就。除此之外,我们还学会了如何在 React 中发出 API 请求并有意义地使用返回的数据。您对 React 作为前端库有什么看法?请在评论中告诉我。

© . All rights reserved.