如何使用UnsplashAPI使用React构建照片搜索应用程序

来自菜鸟教程
跳转至:导航、​搜索

作者选择了 COVID-19 Relief Fund 作为 Write for DOnations 计划的一部分来接受捐赠。

介绍

根据 StackOverflow 2020 开发者调查React 是最流行的 JavaScript 框架之一,这有很多原因,比如有效地改变 web 应用程序视图使用 Virtual DOM[X238X],使用可重用、可组合和有状态的组件来提高可伸缩性等。 初学者 React 开发人员通常需要将他们的知识用于实际应用程序的经验。 本教程将通过向您展示如何使用 React Hooks、使用 useState() 以及在 React 中进行 API 调用来为您提供这种体验。

本文将讨论使用 Unsplash API 使用 React 构建照片搜索应用程序的分步过程。 Unsplash 是目前最常用和流行的照片搜索引擎之一,在构建项目和应用程序时可以成为出色的数据提供者。

在本教程结束时,您将拥有一个使用 React Hooks 查询 Unsplash API 的工作应用程序。 该项目也可以作为样板,因为您可以重复使用相同的编程逻辑,并可以将其用作构建涉及 API 调用的其他项目的基础。 您的照片搜索应用程序将包括一个搜索栏和呈现的结果,如下所示:

如果您想查看完整代码,请查看 DigitalOcean 社区 GitHub 存储库

先决条件

为了遵循本指南:

第 1 步——创建一个空项目

在这一步中,您将使用 Create React App,这将使初始项目运行而无需进行任何手动配置。 在您的项目目录中,运行以下命令。

npx create-react-app react-photo-search

此命令将创建一个名为 react-photo-search 的文件夹,其中包含所有必要的文件和配置,以运行 React Web 应用程序。

使用 cd 命令更改目录并通过运行以下命令进入此文件夹:

cd react-photo-search

接下来,通过运行以下命令启动开发服务器:

npm start

有关此启动脚本的信息,请查看 如何使用 Create React App 设置 React 项目。

接下来,在 Web 浏览器中转到 http://localhost:3000,或者如果您从远程服务器运行,则转到 http://your_domain:3000

你会发现 React 模板:

在进一步移动之前,您必须清理文件。 Create React App 附带了不需要的示例代码,应在构建项目之前将其删除,以确保代码的可维护性。

您现在需要打开另一个终端,因为 npm start 已经占用了一个终端。

通过运行以下命令删除 index.css 中的默认样式:

rm src/index.css

接下来,使用以下命令在代码编辑器中打开 index.js

nano src/index.js

由于您已删除 index.css,请从 index.js 中删除 import './index.css';

index.js 将与此类似。

反应照片搜索/src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

保存并退出文件。

现在通过在终端中运行以下命令来删除 React 徽标:

rm src/logo.svg

使用以下命令打开 App.css

nano src/App.css

App.css 中删除所有内容,然后保存并退出文件。 您将在 Step 3 中使用您的新样式进行更新。

使用以下命令打开 src/App.js

nano src/App.js

下一步是删除 import logo from './logo.svg'; 并使用 App.js 文件中的 className="App"div 中删除 JSX。 这将删除模板的 HTML 元素。

App.js 修改为如下所示:

反应照片搜索/src/App.js

import React from 'react';
import './App.css';

function App() {
  return (
    <div className="App">
         
    </div>
  );
}

export default App;

您的 http://localhost:3000 现在将为空白。

您现在已经初始化了一个 React 应用程序并从中清除了示例代码。 接下来,您将在 Unsplash Developer 仪表板中创建一个新应用程序,并复制您刚刚创建的应用程序的 Access KeySecret Key 以获得对 Unsplash API 的访问权限。

第 2 步 — 获取 Unsplash API 凭证

在本节中,您将申请一个 Unsplash 开发者帐户,为此项目创建一个新应用程序,并复制此应用程序的 Access KeySecret Key 以获得对 Unsplash API 的访问权限。 由于 Unsplash API 不是公共 API,因此您需要为此项目自己的一组 Unsplash API 密钥。

前往 Unsplash 开发者主页 并注册为开发者。 由于您已经创建了 Unsplash 帐户,这将是一个快速的过程。

在 Unsplash Developer 页面上,点击 注册为开发者 按钮。

填写您的凭据以进行注册。

注册为开发人员后,您将被自动重定向到您的 开发人员仪表板。 单击新建应用程序

您将被要求接受 API 使用和指南。 单击复选框,然后单击 Accept terms 按钮以继续:

然后将提示您提供 应用程序信息 。 给您的应用程序一个适当的名称和描述,然后单击创建应用程序

有了这个,您已经创建了一个应用程序,现在可以在 Keys 部分下访问您的 Access KeySecret Key。 将这些密钥复制到安全位置; 您稍后将在代码中需要它们。

请注意,您将在应用程序名称后看到 Demo 标签:

此标记表示您的应用程序处于开发模式,并且请求限制为每小时 50 个。 对于个人项目,这绰绰有余,但您也可以申请生产,这会将请求限制增加到每小时 5000 个。 请记住在申请之前遵循 API 指南

在本节中,您创建了一个 Unsplash API 应用程序并获取了该项目所需的密钥。 对于这个项目,您将使用官方的 Unsplash JavaScript Libraryunsplash-js 将 API 与您的应用程序集成。 在下一步中,您将安装 unsplash.js 并添加 CSS 以设置项目样式。

第 3 步 — 安装依赖项并添加 CSS

您现在将安装 unsplash-js 包作为依赖项,并添加自定义 CSS 来为您的项目设置样式。 如果您在任何时候遇到困难,请参阅此项目的 DigitalOcean 社区存储库

要使用 npm 包管理器 安装 unsplash-js 库,请在项目目录中运行以下命令:

npm install unsplash-js

这是您按照本教程需要安装的唯一库; 稍后,您可以尝试不同的 React 用户界面库,例如 React-BootstrapSemantic UI React 等。 如果在遵循本教程之后,您想要调整此项目并更改其布局,您应该添加这些库。

接下来,您将为您的 React 应用程序设置样式。 通过运行以下命令打开 App.css

nano src/App.css

本教程将逐个讨论 CSS。

首先是 * 选择器,它选择所有元素。 添加以下代码:

反应照片搜索/src/App.css

* {
  box-sizing: border-box;
  background-color: rgb(244, 244, 244);
  color: #333;
  font-size: 10px;
}

box-sizing 属性设置如何计算元素的总宽度和高度,在这种情况下,它告诉浏览器在计算元素的宽度和高度时采用边框和填充。 背景颜色使用 background-color 设置,值为 rgb(244, 244, 244),使背景呈现淡白色。 color 设置元素文本的颜色; 这里使用了十六进制代码 #333,这是一种深灰色阴影。 font-size 设置字体大小。

接下来,添加 .App 块,它选择具有 className="App" 的元素。 默认情况下,父元素 (className="App") 有一些边距和填充,因此以下代码将所有四个边的 marginpadding 设置为 0

反应照片搜索/src/App.css

* {
  box-sizing: border-box;
  background-color: rgb(244, 244, 244);
  color: #333;
  font-size: 10px;
}

.App {
  margin: 0;
  padding: 0;
}

接下来,使用 className="container"div 元素添加样式。 这是带有 className="App"div 的子元素。 包括标题、表单、按钮和图像在内的所有内容都将包含在此 div 中:

反应照片搜索/src/App.css

* {
  box-sizing: border-box;
  background-color: rgb(244, 244, 244);
  color: #333;
  font-size: 10px;
}

.App {
  margin: 0;
  padding: 0;
}

.container {
  margin: 0 auto;
  max-width: 1000px;
  padding: 40px;
}

margin 属性用于定义元素周围的空间。 可以为 toprightbottomleft 设置 margin。 如果仅添加一个值,则将为所有 toprightbottomleft 设置该值。 如果在 margin 中添加两个值,则第一个值将设置为 topbottom,第二个值将设置为 right 和 [ X153X]。

根据 margin: 0 auto;topbottom0 边距,而 leftrightauto ]。 这个 auto 表示浏览器会根据容器设置边距。 理解这一点的一个例子是,如果父元素是 100px,子元素是 50px,那么 leftright 边距将为 [ X163X],这将使子元素在父元素内居中。

max-width 设置元素的 width 的最大值,在本例中为 1000px。 如果内容大于1000px,则元素的height属性会相应改变,否则max-width无效。

如上所述,margin 设置元素周围的空间,而 padding 设置元素与其内容之间的空间。 较早的代码意味着 container div 和其中的元素将在它们之间从所有四个侧面具有 40px 的空间。

接下来,为应用程序的标题添加样式:

反应照片搜索/src/App.css

...
.container {
  margin: 0 auto;
  max-width: 1000px;
  padding: 40px;
}

.title {
  font-size: 4.4rem;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
}

.title 对应您的 App 的标题,即“React Photo Search”。 只设置了两个属性,分别是font-sizefont-family。 此处,rem 单位用于 font-size 值。 rem 值是相对于根 html 元素的,不像 em 值是相对于父元素的。 这里的 4.4rem 表示 44px (4.4 x 10)。 这个乘以 10px 是因为您使用 * 选择器将所有元素的字体大小设置为 10pxfont-family 指定元素的字体。 代码中传递了许多值来充当 fallback 系统; 如果浏览器不提供第一种字体,则设置下一种字体。

接下来是 .form CSS 块,其中包括将用于搜索图像的表单。 这包括输入搜索字段、按钮和标签。

反应照片搜索/src/App.css

...
.title {
  font-size: 4.4rem;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
}

.form {
  display: grid;
}

这里只设置了 display 属性。 此属性指定元素的显示行为。 它可以采用不同的值,例如 gridflexblockinline 等。 grid 将元素显示为块级,并根据 网格模型 呈现内容。

接下来是 .label.input CSS 块:

反应照片搜索/src/App.css

...
.form {
  display: grid;
}

.label {
  font-size: 3rem;
  margin-bottom: 1rem;
}

.input {
  font-size: 1.6rem;
  padding: 0.5rem 2rem;
  line-height: 2.8rem;
  border-radius: 20px;
  background-color: white;
  margin-bottom: 1rem;
}

我们已经讨论过 font-sizepaddingbackground-colormargin-bottom,所以让我们讨论 line-heightborder-radiusborder-radius 定义元素角的半径。 这里的值设置为 20px,它将用于所有四个边。 将 border-radius 设置为 50% 可以使正方形元素变成椭圆形。 line-height 指定线的高度,设置为 2.8rem28px

接下来是 .button CSS 块,用于设置 Search 按钮的样式:

反应照片搜索/src/App.css

...
.input {
  font-size: 1.6rem;
  padding: 0.5rem 2rem;
  line-height: 2.8rem;
  border-radius: 20px;
  background-color: white;
  margin-bottom: 1rem;
}

.button {
  background-color: rgba(0, 0, 0, 0.75);
  color: white;
  padding: 1rem 2rem;
  border: 1px solid rgba(0, 0, 0, 0.75);
  border-radius: 20px;
  font-size: 1.4rem;
  cursor: pointer;
  transition: background-color 250ms;
}

我们已经讨论过 background-colorcolorpaddingborder-radiusfont-sizeborder 设置元素边框的样式、宽度和颜色。 这里 border 用作 border-widthborder-styleborder-color 的简写属性。 此代码在 Search 按钮周围添加了一个 1px 的纯黑色边框。 cursor 指定鼠标光标指向一个元素时。

接下来是 :hover 选择器,用于 .button

反应照片搜索/src/App.css

...
.button {
  background-color: rgba(0, 0, 0, 0.75);
  color: white;
  padding: 1rem 2rem;
  border: 1px solid rgba(0, 0, 0, 0.75);
  border-radius: 20px;
  font-size: 1.4rem;
  cursor: pointer;
  transition: background-color 250ms;
}

.button:hover {
  background-color: rgba(0, 0, 0, 0.85);
}

这意味着当鼠标悬停在 .button 元素上时,背景颜色会发生变化。

下一个 CSS 块是 .card-list,它对应于 divclassName="card-list"。 这个 div 将显示其中的所有图像:

反应照片搜索/src/App.css

...
.button:hover {
  background-color: rgba(0, 0, 0, 0.85);
}

.card-list {
  column-count: 3;
}

column-count 根据在元素内部传递的值将元素分成列。 这段代码将card-list div分成三列,图片会显示在这三列中。

接下来是 .card.card--image CSS 块。 .card 指的是单个的 div 里面有一个图像,而 .card--image 是这个图像的 className

反应照片搜索/src/App.css

...
.card-list {
  column-count: 3;
}

.card {
    margin-bottom: 1rem;
    display: flex;
}

.card--image {
    flex: 100%;
    margin-top: 1rem;
    border-radius: 10px;
}

我们已经讨论过 margindisplayborder-radius。 在.card中,display设置为flex,表示元素会表现得像块元素,显示会根据flexbox模型 ]。 通过使用简写属性 flex:100%;,您可以设置 flex-growflex-shrinkflex-basis 的值。 您可以在 Mozilla 开发者网络 上阅读有关它的更多信息

最终的 CSS 块涉及 媒体查询 。 通过使用 @media 规则,您可以为不同的媒体类型/设备应用不同的样式:

反应照片搜索/src/App.css

...
.card--image {
    flex: 100%;
    margin-top: 1rem;
    border-radius: 10px;
}

@media (min-width: 768px) {
  .form {
    grid-template-columns: auto 1fr auto;
    grid-gap: 1rem;
    align-items: center;
  }
  .input {
    margin-bottom: 0;
  }
}

@media only screen and (max-width: 600px) {
    .card-list {
        column-count: 1;
    }
}

根据此代码,当浏览器窗口为 600px 或更小时(适用于大多数移动设备)时,column-count 将从 3 变为 1。 这将 max-width 属性与 @media 规则一起使用。 之前的代码使用 min-width,当宽度为 768px 或更大时,它会改变 @media 规则内元素的样式。

grid-template-columns 用于指定网格模型中的列。 列数等于传递的值的个数,根据代码是三个( auto 1fr auto)。 第一个和第三个网格元素的大小将取决于它们的容器大小或内容的大小。 第二个元素将被赋予 1fr(分数单位),或者根据它们的大小,在第一个和第三个元素占据之后剩余的空间。 这三个元素将是相机表情符号、搜索输入字段和 Search 按钮。 表情符号和按钮根据大小占用空间后,其余区域将进入搜索输入字段,并相应更改其宽度。

grid-gap: 1rem; 在两条网格线之间创建一个 1rem 的空间。 align-items:center; 将项目定位在容器的中心。

这样就完成了应用程序的样式。 保存并退出src/App.css。 如果您想一起查看整个 CSS 文件,请查看此代码的 GitHub 存储库

现在您已经安装了必要的依赖项并添加了为项目设置样式所需的自定义 CSS,您可以继续下一部分并设计项目的 UI 或布局。

第 4 步 — 设计用户界面

在本节中,您将设计项目的 UI。 这将包括标题、标签、输入字段和按钮等元素。

使用以下命令打开 src/App.js 文件:

nano src/App.js

要为您的项目添加标题,请在 App.js 中使用 className="container" 创建一个 div。 在这个 div 中添加一个带有 className="title"h1 标签,并在标签内写入 React Photo Search。 这将是标题:

反应照片搜索/src/App.js

import React from 'react';
import './App.css';

function App() {
  return (
    <div className="App">
      <div className="container">
        <h1 className="title">React Photo Search</h1>
      </div>
    </div>
  );
}

保存并退出文件。 在您的浏览器中,您的应用现在将显示您的标题:

接下来,您将创建一个接收用户输入的表单。 此表单将包含一个输入文本字段和一个提交按钮。

为此,创建一个名为 <SearchPhotos /> 的新 组件。 不必创建单独的组件,但在开发此项目时,将代码拆分为组件可以更轻松地编写和维护代码。

src 文件夹中,使用以下命令创建并打开一个名为 searchPhotos.js 的新文件:

nano src/searchPhotos.js

searchPhotos.js 中,导出一个名为 <SearchPhotos /> 的函数组件:

反应照片搜索/src/searchPhotos.js

import React from "react";

export default function SearchPhotos() {
  return (
    <>

    </>
  );
}

这是您需要添加到 searchPhotos.js 文件中的功能组件的基本结构。 保存此文件。

下一步是在App.js中导入并使用SearchPhotos组件。

在新的终端窗口中,打开 App.js

nano src/App.js

将以下突出显示的行添加到 App.js

反应照片搜索/src/App.js

import React from "react";
import "./App.css";
import SearchPhotos from "./searchPhotos"

function App() {
  return (
    <div className="App">
      <div className="container">
        <h1 className="title">React Photo Search</h1>
        <SearchPhotos />

      </div>
    </div>
  );
}
export default App;

保存此文件。

要创建搜索表单,您将使用 form 标签并在其中使用 input 标签创建一个输入字段,并使用 button 标签创建一个按钮。

给元素各自标签的 className。 在执行此操作时,添加一个带有相机表情符号的标签以进行样式设置:

反应照片搜索/src/searchPhotos.js

...
export default function SearchPhotos() {
  return (
    <>
      <form className="form"> 
        <label className="label" htmlFor="query"> 
          {" "}
          📷
        </label>
        <input
          type="text"
          name="query"
          className="input"
          placeholder={`Try "dog" or "apple"`}
        />
        <button type="submit" className="button">
          Search
        </button>
      </form>
    </>
  );
}

首先,您创建了一个带有 className="form"form 元素,并在其中创建了一个带有相机表情符号的 label。 然后是带有属性 type="text"input 元素,因为搜索查询将是 stringname="query" 属性指定 input 元素的名称,className="input" 给元素一个样式类,搜索栏的占位符值设置为 [ X177X]。 form 中的最后一个元素是带有 type="submit"button

保存并退出文件。 您的应用现在将在标题后有一个搜索栏:

现在应用程序的 UI 已经完成,您可以通过首先在下一部分中存储来自用户的输入查询来开始处理功能。

第 5 步 - 使用搜索查询设置状态

在这一步中,您将了解 statesReact Hooks,然后使用它们来存储用户输入。

现在您已经构建了应用程序的基本结构,我们可以讨论 React 方面的事情。 您有一个表单,但它还没有做任何事情,所以首先要做的是从搜索栏中获取输入并访问它。 您可以对状态执行此操作。

状态的核心是 对象 ,用于存储组件的属性值。 每次状态改变时,组件都会重新渲染。 对于此应用程序,您需要一个状态,该状态将在单击 Search 按钮时存储来自搜索栏的输入或查询。

您可能已经注意到的一件事是该项目正在使用功能组件。 这允许您使用 React Hooks 来管理状态。 Hooks 是使用 React 特性的函数,例如在不编写类的情况下定义状态。 在本教程中,您将使用 useState() Hook。

首先要做的是在您的 searchPhotos.js 文件中导入 useState

打开文件:

nano src/searchPhotos.js

修改searchPhotos.js文件的第一行如下:

反应照片搜索/src/searchPhotos.js

import React, { useState } from "react";

export default function SearchPhotos() {
...

接下来,您将实现 useState()。 这是 useState() 钩子的语法:

useState(initialState)

useState() 返回当前状态和一个通常称为更新函数的函数。 要存储这些,您可以使用 array destructuring

const [query, setQuery] = useState(initialState);

在这个例子中,query 存储了组件的当前状态,setQuery 是一个可以被调用来更新状态的函数。 initialState 定义初始状态值; 它可以是字符串、数字、数组或对象,具体取决于用途。

在您的项目中,来自搜索栏的输入是一个字符串,因此您将使用一个空字符串作为状态的初始值。

在您的 searchPhotos.js 文件中,添加以下代码行:

反应照片搜索/src/searchPhotos.js

...

export default function SearchPhotos() {
  const [query, setQuery] = useState("");
 
  return (
    <>
      <form className="form">
        <label className="label" htmlFor="query">
          {" "}
          📷
        </label>
...

下一步是将输入文本字段的 value 设置为 query 并向其添加 onChange() 事件。 这个 onChange() 事件将有一个函数,其中 setQuery() 将用于更新状态。 使用 e.target.value 检索输入字符串:

反应照片搜索/src/searchPhotos.js

...
<input
    type="text"
    name="query"
    className="input"
    placeholder={`Try "dog" or "apple"`}
    value={query}
    onChange={(e) => setQuery(e.target.value)}
/>
...

现在,状态和输入字段的值是相互关联的,您可以使用此搜索查询来搜索图像。

您可以实时查看 query 内搜索栏中的输入以进行测试。 在您定义状态的位置之后添加 console.log(query)

反应照片搜索/src/searchPhotos.js

...
export default function SearchPhotos() {
   const [query, setQuery] = useState("");
   console.log(query);

  return (
    <>
    //
    </>
  );
}

保存文件。

您现在将在控制台内收到输入查询。 您可以使用 Chrome 中的 F12Firefox 中的 Ctrl+Shift+K 打开控制台:

现在,searchPhotos.js 将如下所示:

反应照片搜索/src/searchPhotos.js

import React, { useState } from "react";
export default function SearchPhotos() {
  const [query, setQuery] = useState("");
  console.log(query);

  return (
    <>
      <form className="form">
        <label className="label" htmlFor="query">
          {" "}
          📷
        </label>
        <input
          type="text"
          name="query"
          className="input"
          placeholder={`Try "dog" or "apple"`}
          value={query}
          onChange={(e) => setQuery(e.target.value)}
        />
        <button type="submit" className="button">
          Search
        </button>
      </form>
    </>
  );
}

本节讨论了状态和 React Hooks,并将用户输入存储在 query 状态内的 input 字段中。 在下一部分中,您将使用此搜索查询来搜索图像并将响应存储在另一个状态中。

第 6 步 — 向 Unsplash 发出 API 请求

您现在将使用 unsplash-js 库通过 input 字段中的查询来搜索图像。 响应将存储在另一个名为 pics 的状态中。

您已经安装了 unsplash-js 库,因此将其导入 searchPhotos.js 文件。 您还可以从上一节中删除 console.log() 语句:

反应照片搜索/src/searchPhotos.js

import React, { useState } from "react";
import Unsplash, { toJson } from "unsplash-js";

...

toJsonunsplash-js 库中的辅助函数,用于将响应转换为 JSON 格式。 您可以在 unsplash-js GitHub 页面 上了解有关辅助函数的更多信息。

要在您的应用程序中使用 Unsplash,请使用 new 关键字创建它的实例,如下所示:

反应照片搜索/src/searchPhotos.js

import React, { useState } from "react";
import Unsplash, { toJson } from "unsplash-js";

const unsplash = new Unsplash({
  accessKey: "your_Access_Key",
});

粘贴您的 Unsplash Access Key 以替换 your_Access_Key,您现在可以发出 API 请求。

警告: 永远不应共享任何 API 或任何服务的访问密钥或客户端 ID。 潜在的不良行为者可能会在互联网上滥用它们。 在这种情况下,他们可以发出异常数量的请求,这些请求可能会被您的服务提供商标记为垃圾邮件,这可能会停用您的应用程序和帐户。


现在您将创建一个 异步函数,当单击 Search 按钮时将触发该函数。

在为 query 定义状态之后,定义一个 async 函数:

反应照片搜索/src/searchPhotos.js

...
export default function SearchPhotos() {
  const [query, setQuery] = useState("");

  const searchPhotos = async (e) => {
    e.preventDefault();
    console.log("Submitting the Form")
  };

每当单击 Search 按钮时,此处 e.preventDefault() 都会停止重新加载页面。 您可以在 form 标签内的 onSubmit 事件中传递此函数。 您可以在 官方 React 文档 中阅读更多相关信息。

反应照片搜索/src/searchPhotos.js

...
  return (
    <>
      <form className="form" onSubmit={searchPhotos}>
...

保存文件。 现在,如果您单击 Search 按钮,您将在控制台中收到 Submitting the Form。 您可以在控制台成功响应后删除此 console.log()

searchPhotos() 函数中,您将使用 Unsplash 实例 (unsplash)。 您可以使用 search 方法搜索图像。 这是它的语法:

search.photos(keyword, page, per_page, filters)

这是搜索图像的代码; 在 searchPhotos() 函数中添加此代码:

反应照片搜索/src/searchPhotos.js

...
const searchPhotos = async (e) => {
  e.preventDefault();
  unsplash.search
    .photos(query)
    .then(toJson)
    .then((json) => {
      console.log(json);
    });
};
...

首先,您使用 unsplash.search,然后指定要搜索的内容,在本例中为 photos。 我们也可以搜索 userscollectionsphotos 将第一个必填参数作为要搜索的关键字,即query; 您还可以通过可选参数指定页面、每页响应、图像方向等。 对于本教程,您只需要 pageper_page 参数,限制您从 Unsplash 获得的响应项。

以下是 photos 中可以提供的所有参数

争论 类型 选择/必需 默认
keyword 细绳 必需的
page 数字 选修的
per_page 数字 选修的 10
filters 目的 选修的
filters.orientation 细绳 选修的
filters.collections 大批 选修的

您可以在 unsplash-js GitHub 页面 上了解有关它们的更多信息。

您使用 toJson 方法将响应转换为 JSON,最后使用 console.log() 响应来测试 API 请求是否没有任何错误。 您将在接下来的步骤中删除此 console .log ()

保存文件。 现在打开您的控制台并单击 Search 按钮。 你会发现这样的响应 JSON:

{
  "results": [{
     "description": "Pink Wall Full of Dogs",
     "alt_description": "litter of dogs fall in line beside wall",
     "urls": {
           "raw": "https://images.unsplash.com/photo-1529472119196-cb724127a98e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjE0MTQxN30",
           "full": "https://images.unsplash.com/photo-1529472119196-cb724127a98e?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0MTQxN30",
           "regular": "https://images.unsplash.com/photo-1529472119196-cb724127a98e?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjE0MTQxN30",
           "small": "https://images.unsplash.com/photo-1529472119196-cb724127a98e?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0MTQxN30",
           "thumb": "https://images.unsplash.com/photo-1529472119196-cb724127a98e?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&ixid=eyJhcHBfaWQiOjE0MTQxN30"
                },
    ...
}

当您发现 Unsplash API 成功响应时,您可以删除或注释 console.log() 语句,这意味着您的代码运行正常。 此应用程序将使用 "urls" 字段,因为这将是图像的来源。

现在,当使用 unsplash-js 库单击 Search 按钮时,您已经使用来自用户的查询来搜索图像。 接下来,您将把响应存储在另一个名为 pics 的状态中,并通过映射此状态中的元素来显示图像。

第 7 步 — 在网页上显示图像

在最后一部分中,您将把来自 Unsplash API 的响应存储在另一个名为 pics 的状态中,然后映射该状态的元素以在网页上显示图像。

要显示图像,您需要访问响应 JSON,为此,需要另一个状态。 之前的状态 query 存储来自用户的查询,用于向 Unsplash API 发出请求。 此状态 pics 将存储您从 Unsplash API 获得的图像响应。

searchPhotos.js 中定义另一个状态,如下所示:

反应照片搜索/src/searchPhotos.js

...
  const [query, setQuery] = useState("");
  const [pics, setPics] = useState([]);
...

这个状态已经用一个空的 array 初始化,所有的响应都将作为一个对象存储在这个状态中。 换句话说,这是一个对象数组。

要使用 JSON 更新此状态,您将在 unsplash API 请求中使用 setPics

反应照片搜索/src/searchPhotos.js

...
    unsplash.search
      .photos(query, 1, 20)
      .then(toJson)
      .then((json) => {
        setPics(json.results);
  });
...

现在,每次您搜索新查询时,此状态都会相应更新。

接下来,在 form 标签结束的地方创建一个带有 className="card-list"div

反应照片搜索/src/searchPhotos.js

...
        <button type="submit" className="button">
          Search
        </button>
      </form>
      <div className="card-list">
      </div>
    </>
  );
}

在这个 div 内部,您将映射状态并显示图像的 id

反应照片搜索/src/searchPhotos.js

...
        <button type="submit" className="button">
          Search
        </button>
      </form>
      <div className="card-list">
        {pics.map((pic) => pic.id )}
      </div>
    </>
  );
}

您首先使用 {} 传递 JavaScript 表达式,在其中您使用 .map() 方法 在您的状态。

保存您的文件。 如果您现在搜索,您将看到与网页上不同对象关联的 id

这很混乱,但这也意味着您的应用程序正在运行。

不要显示 pic.id,而是在 map 函数中打开 JSX,并使用 className="card" 创建一个新的 div。 这将是每个单独图像的容器:

反应照片搜索/src/searchPhotos.js

...
        <button type="submit" className="button">
          Search
        </button>
      </form>
      <div className="card-list">
        {
          pics.map((pic) => <div className="card"></div>);
        }
      </div>
    </>
  );
}

您现在可以在此 div 中显示图像:

反应照片搜索/src/searchPhotos.js

...
        <button type="submit" className="button">
          Search
        </button>
      </form>
      <div className="card-list">
        {
          pics.map((pic) => 
            <div className="card">
              <img
                className="card--image"
                alt={pic.alt_description}
                src={pic.urls.full}
                width="50%"
                height="50%"
              ></img>
            </div>);
        }
      </div>
    </>
  );
}

如果你回去查看响应 JSON,你会发现不同类型的信息。 "urls" 包含图片的路径,所以这里的 pic.urls.full 是图片的实际路径,pic.alt_description 是图片的 alt 描述。

"urls" 内部有不同的字段提供不同的数据,例如:

raw :用户实际拍摄的原始图像。 full : .jpg 格式的原始图像。 regular:最适合实际使用,width=1080pxsmall :适合网速较慢的 width=400pxthumb :图像的缩略图版本,width=200px

在本教程中,您使用的是 full,但您也可以尝试其他类型。 您还为图像提供了默认的 heightwidth

保存您的文件。

您的申请即将完成; 如果您现在搜索,您将能够看到您的应用程序正在运行。 但是还剩下一小行代码。 如果您搜索图像并在浏览器中转到控制台,您将看到一条警告。

Web consoleWarning: Each child in a list should have a unique "key" prop.

要解决此问题,请使用图像的 id 将唯一的 key 传递给每个孩子。 这个 key prop 明确地告诉 React 列表中每个孩子的身份; 这也可以防止孩子在渲染之间丢失状态:

反应照片搜索/src/searchPhotos.js

...
      <div className="card-list">
        {pics.map((pic) =>
          <div className="card" key={pic.id}>
            <img
              className="card--image"
              alt={pic.alt_description}
              src={pic.urls.full}
              width="50%"
              height="50%"
            ></img>
          </div>)};
      </div>
    </>
  );
}

您可以通过将相应的参数传递给 unsplash.search.photos() 来调整要显示的图像数量。

保存并退出文件。 您现在将拥有一个正常工作的照片搜索应用程序:

在本节中,您将来自 Unsplash API 的响应存储在 pics 状态中,并通过映射 pics 中的元素来显示图像。

结论

在本教程中,您使用 Unsplash API 开发了一个 React Photo Search 应用程序。 在构建项目时,本教程讨论了如何使用 React Hooks、查询 API 和设置用户界面样式。

这个应用程序可以做很多事情来扩展它。 例如,您可以添加一个 Random 按钮来显示随机图像,创建一个复选框以根据用户的偏好在搜索照片或发布照片的用户之间切换,添加一个 无限滚动 [X227X ] 以显示更多图像等。 您也可以使用相同的概念并制作涉及 API 请求的其他项目,例如 Hacker News API

如果您想查看更多 React 教程,请查看我们的 React 主题页面