作者选择了COVID-19 救济基金来接受捐赠,作为Write for DOnations计划的一部分。
介绍
根据StackOverflow 2020 开发人员调查,React是最受欢迎的JavaScript框架之一,其原因有很多,例如使用Virtual DOM有效更改 Web 应用程序视图,使用可重用、可组合和有状态的组件来提高可扩展性,以及更多的。初学者 React 开发人员通常需要将他们的知识用于实际应用程序的经验。本教程将通过向您展示如何在React中使用React Hooks、使用useState()
和进行 API 调用来为您提供这种体验。
本文将讨论使用Unsplash API使用 React 构建照片搜索应用程序的分步过程。Unsplash 是目前最常用和最流行的照片搜索引擎之一,在构建项目和应用程序时可以成为一个很好的数据提供者。
在本教程结束时,您将拥有一个使用 React Hooks 查询 Unsplash API 的工作应用程序。该项目还可以充当样板,因为您可以重用相同的编程逻辑,并将其用作构建涉及 API 调用的其他项目的基础。您的照片搜索应用程序将包括一个搜索栏和呈现的结果,如下所示:
如果您想查看完整代码,请查看DigitalOcean 社区 GitHub 存储库。
先决条件
为了遵循本指南:
-
您将需要一个免费的 Unsplash 帐户,您可以在Unsplash 官方网站上获得该帐户。
-
你需要一个运行Node.js的开发环境;本教程在 Node.js 版本 10.20.1 和 npm 版本 6.14.4 上进行了测试。要在 macOS 或 Ubuntu 18.04 上安装它,请按照如何在 macOS 上安装 Node.js 和创建本地开发环境或如何在 Ubuntu 18.04 上安装 Node.js 的使用 PPA 安装部分中的步骤进行操作。
-
您还需要具备 JavaScript 和 HTML 的基本知识,您可以在我们的如何使用 HTML 构建网站系列和如何在 JavaScript 中编码中找到这些知识。CSS 的基本知识也很有用,您可以在Mozilla 开发人员网络找到这些知识。
第 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 项目。
接下来,转到http://localhost:3000
Web 浏览器,或者如果您从远程服务器运行它,则.http://your_domain:3000
你会发现 React 模板:
在进一步移动之前,您必须清理文件。Create React App 附带了一些不需要的示例代码,应该在构建项目之前将其删除以确保代码可维护性。
您现在需要打开另一个终端,因为一个终端已经被npm start
.
index.css
通过运行以下命令删除默认样式:
- rm src/index.css
接下来,index.js
使用以下命令在代码编辑器中打开:
- nano src/index.js
由于您已删除index.css
,请import './index.css';
从 中删除index.js
。
index.js
完成删除后import ./index.css
,您将与此类似。
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
,然后保存并退出文件。您将在第 3 步中使用新样式进行更新。
src/App.js
使用以下命令打开:
- nano src/App.js
下一步骤是去除import logo from './logo.svg';
并取出JSX从div
与className="App"
在App.js
文件中。这将删除模板的 HTML 元素。
修改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 Key
和Secret Key
以访问 Unsplash API。
第 2 步 – 获取 Unsplash API 凭证
在本节中,您将申请一个 Unsplash 开发者帐户,为此项目创建一个新应用程序,并复制该应用程序的Access Key
和Secret Key
以获得对 Unsplash API 的访问权限。由于 Unsplash API 不是公共 API,因此您需要为该项目设置自己的 Unsplash API 密钥集。
前往Unsplash 开发人员主页并注册为开发人员。由于您已经创建了一个 Unsplash 帐户,这将是一个快速的过程。
在 Unsplash Developer 页面上,单击Register as a developer按钮。
填写您的凭据进行注册。
注册为开发人员后,您将被自动重定向到您的开发人员仪表板。单击“新建应用程序”。
您将被要求接受API 使用和指南。单击复选框,然后单击接受条款按钮以进一步进行:
然后将提示您提供您的应用程序信息。为您的应用程序提供适当的名称和描述,然后单击创建应用程序。
有了这个,你已经创建了一个应用程序,现在可以访问Access Key
和Secret Key
下键部分。将这些密钥复制到安全位置;您稍后将在代码中需要它们。
请注意,您将在应用程序名称后看到一个Demo标签:
此标记表示您的应用程序处于开发模式并且请求限制为每小时 50 个。对于个人项目,这已经绰绰有余,但您也可以申请生产,这会将请求限制增加到每小时 5000 个。请记住在申请前遵循API 指南。
在本节中,您创建了一个 Unsplash API 应用程序并获得了该项目所需的密钥。对于这个项目,你会使用官方Unsplash JavaScript库,unsplash-js
到API与您的应用程序集成。unsplash.js
在下一步中,您将安装并添加 CSS 以设置项目的样式。
第 3 步 – 安装依赖项并添加 CSS
您现在将安装该unsplash-js
包作为依赖项并添加自定义 CSS 以设置您的项目样式。如果您遇到任何问题,请参阅此项目的DigitalOcean 社区存储库。
要unsplash-js
使用npm 包管理器安装库,请在项目目录中运行以下命令:
- npm install unsplash-js
这是您按照本教程需要安装的唯一库;稍后,您可以尝试使用不同的 React 用户界面库,例如React-Bootstrap、Semantic UI React等。如果在遵循本教程之后,您想要调整此项目并更改其布局,则应该添加这些库。
接下来,您将设置 React 应用程序的样式。App.css
通过运行以下命令打开。
- nano src/App.css
本教程将逐个讨论 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"
) 有一些边距和填充,因此以下代码将所有四个边的margin
和设置padding
为0
:
* {
box-sizing: border-box;
background-color: rgb(244, 244, 244);
color: #333;
font-size: 10px;
}
.App {
margin: 0;
padding: 0;
}
接下来,div
使用className="container"
. 这是div
with的子元素className="App"
。包括标题、表单、按钮和图像在内的所有内容都将包含在此div
:
* {
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
属性用于定义元素周围的空间。margin
可以设定top
,right
,bottom
,和left
。如果只添加一个值,那么这一个值将所有设置top
,right
,bottom
,和left
。如果在 中添加两个值margin
,则第一个值将设置为top
and bottom
,第二个值将设置为right
and left
。
据margin: 0 auto;
,top
并且bottom
有0
利润,而left
和right
有auto
。这auto
意味着浏览器将根据容器设置边距。理解这一点的一个示例是,如果父元素是100px
,子元素是50px
,则left
和right
边距将是25px
,这将使子元素在父元素内居中。
max-width
设置width
元素的最大值,在本例中为1000px
。如果内容大于1000px
,则height
元素的属性会相应改变,否则max-width
无效。
如上所述,margin
设置元素周围的空间,同时padding
设置元素与其内容之间的空间。较早的代码意味着它container
div
内部的和 元素40px
之间将有四个边的空间。
接下来,为应用程序的标题添加样式:
...
.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
对应于您的应用程序的标题,即“React Photo Search”。只设置了两个属性,即font-size
和font-family
。此处,rem
单位用于font-size
值。rem
值是相对于根html
元素的,不像em
值是相对于父元素的。这里的4.4rem
意思是44px
(4.4 x 10)。这种乘法10px
是因为您将所有元素的字体大小设置为10px
使用*
选择器。font-family
指定元素的字体。代码中传递了许多值作为回退系统;如果浏览器不提供第一种字体,则设置下一种字体。
接下来是.form
CSS 块,其中包含将用于搜索图像的表单。这包括输入搜索字段、按钮和标签。
...
.title {
font-size: 4.4rem;
font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
}
.form {
display: grid;
}
在这里,只display
设置了属性。此属性指定元素的显示行为。它可以采用不同的值,如grid
、flex
、block
、inline
等。grid
将元素显示为块级并根据网格模型呈现内容。
接下来是.label
和.input
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-size
, padding
, background-color
, 和margin-bottom
,所以让我们讨论line-height
和border-radius
。border-radius
定义元素角的半径。此处将该值设置为20px
,将用于所有四个边。设置border-radius
为50%
可以将方形元素变成椭圆形。line-height
指定行的高度,设置为2.8rem
或28px
。
接下来是.button
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-color
,color
,padding
,border-radius
,和font-size
。border
设置元素边框的样式、宽度和颜色。这里border
被用作速记属性border-width
,border-style
和border-color
。此代码在“搜索”按钮周围添加了 1 像素的纯黑色边框。cursor
指定鼠标指针指向元素时的光标。
接下来是:hover
选择器,它用于.button
.
...
.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
,它对应于div
with className="card-list"
。这div
将显示其中的所有图像:
...
.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
此图像的 :
...
.card-list {
column-count: 3;
}
.card {
margin-bottom: 1rem;
display: flex;
}
.card--image {
flex: 100%;
margin-top: 1rem;
border-radius: 10px;
}
我们已经讨论过margin
,display
和border-radius
。在.card
,display
设置为flex
,这意味着元素将表现得像块元素,并且显示将根据flexbox 模型设置。通过使用速记属性flex:100%;
,您可以设置值flex-grow
,flex-shrink
和flex-basis
。您可以在 Mozilla Developer Network阅读更多相关信息。
最后的 CSS 块涉及媒体查询。通过使用该@media
规则,您可以为不同的媒体类型/设备应用不同的样式:
...
.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;
}
}
根据这个代码,column-count
将从改变3
到1
当浏览器窗口是600px
以下(适用于多数移动设备)。这将max-width
属性与@media
规则一起使用。之前的代码使用min-width
,@media
当宽度为768px
或更大时改变规则内元素的样式。
grid-template-columns
用于指定网格模型中的列。列数等于传递的值数,根据代码(auto 1fr auto
)为三。第一个和第三个网格元素的大小将取决于它们的容器大小或内容的大小。将给出第二个元素1fr
(Fractional Unit),或根据它们的大小占用第一个和第三个元素后留下的空间。这三个元素将是相机表情符号、搜索输入字段和搜索按钮。表情符号和按钮根据其大小占用空间后,其余区域将进入搜索输入字段,并相应地更改其宽度。
grid-gap: 1rem;
1rem
在两条网格线之间创建一个空间。align-items:center;
将项目放置在容器的中心。
这样就完成了应用程序的样式。保存并退出src/App.css
。如果您想一起查看整个 CSS 文件,请查看此代码的GitHub 存储库。
现在您已经安装了必要的依赖项并添加了为您的项目设置样式所需的自定义 CSS,您可以前进到下一部分并设计项目的 UI 或布局。
第 4 步 – 设计用户界面
在本节中,您将设计项目的 UI。这将包括标题、标签、输入字段和按钮等元素。
src/App.js
使用以下命令打开文件:
- nano src/App.js
要将标题添加到您的项目中,创建一个div
与className="container"
你的里面App.js
。在这个里面div
添加一个h1
带有 的标签className="title"
并写React Photo Search
在标签里面。这将是标题标题:
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 />
:
import React from "react";
export default function SearchPhotos() {
return (
<>
</>
);
}
这是您需要添加到searchPhotos.js
文件中的功能组件的基本结构。保存此文件。
下一步是导入和使用SearchPhotos
的组件App.js
。
在新的终端窗口中,打开App.js
:
- nano src/App.js
将以下突出显示的行添加到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
各自的标签。在执行此操作时,添加一个带有相机表情符号的标签以进行样式设置:
...
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>
</>
);
}
首先,您创建了一个form
带有 a的元素className="form"
,并在其中创建了一个label
带有相机表情符号的a元素。然后是input
带有属性的元素type="text"
,因为搜索查询将是一个字符串。该name="query"
属性指定input
元素的名称,为元素className="input"
提供样式类,搜索栏的占位符值设置为Try "dog" or "apple"
。中的最后一个元素form
是button
带有type="submit"
.
保存并退出文件。您的应用现在将在标题后面有一个搜索栏:
现在应用程序的 UI 已经完成,您可以通过在下一部分中首先存储来自用户的输入查询来开始处理功能。
第 5 步 – 使用搜索查询设置状态
在这一步中,您将了解状态和React Hooks,然后使用它们来存储用户输入。
现在您已经构建了应用程序的基本结构,我们可以讨论 React 方面的事情。您有一个表单,但它还没有做任何事情,所以首先要做的是从搜索栏中获取输入并访问它。你可以用状态来做到这一点。
在他们的核心国家是对象是用于存储组件的属性值。每次状态改变时,组件都会重新渲染。对于此应用程序,您需要一个状态,以便在单击“搜索”按钮时存储来自搜索栏中的输入或查询。
您可能已经注意到的一件事是该项目正在使用功能组件。这允许您使用 React Hooks 来管理状态。Hook 是使用 React 功能的函数,例如无需编写类即可定义状态。在本教程中,您将使用useState()
Hook。
首先要做的是useState
在searchPhotos.js
文件中导入。
打开文件:
- nano src/searchPhotos.js
将searchPhotos.js
文件的第一行修改为以下内容:
import React, { useState } from "react";
export default function SearchPhotos() {
...
接下来,您将实现useState()
. 这是useState()
钩子的语法:
useState(initialState)
useState()
返回当前状态和通常称为更新程序函数的函数。要存储这些,您可以使用数组解构:
const [query, setQuery] = useState(initialState);
在这个例子中,query
存储了组件的当前状态,setQuery
是一个可以被调用来更新状态的函数。initialState
定义初始状态值;它可以是字符串、数字、数组或对象,具体取决于用途。
在您的项目中,搜索栏的输入是一个字符串,因此您将使用一个空字符串作为状态的初始值。
在您的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
以下方法检索输入字符串:
...
<input
type="text"
name="query"
className="input"
placeholder={`Try "dog" or "apple"`}
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
...
现在,状态和输入字段的值相互关联,您可以使用此搜索查询来搜索图像。
您可以实时查看来自内部搜索栏的输入以query
进行测试。console.log(query)
在您定义状态的位置之后添加:
...
export default function SearchPhotos() {
const [query, setQuery] = useState("");
console.log(query);
return (
<>
//
</>
);
}
保存文件。
您现在将在控制台内收到输入查询。您可以打开控制台,使用F12
的浏览器或Ctrl+Shift+K
在Firefox中:
现在,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,并将用户输入存储input
在query
状态内的字段中。在下一节中,您将使用此搜索查询来搜索图像并将响应存储在另一个状态中。
第 6 步 – 向 Unsplash 发出 API 请求
现在,您将使用unsplash-js
库通过input
字段中的查询来搜索图像。响应将存储在另一个名为pics
.
您已经安装了该unsplash-js
库,因此将其导入到searchPhotos.js
文件中。您还可以删除console.log()
上一节中的语句:
import React, { useState } from "react";
import Unsplash, { toJson } from "unsplash-js";
...
toJson
是unsplash-js
库中的一个辅助函数,用于将响应转换为JSON 格式。您可以在unsplash-js
GitHub 页面了解有关辅助函数的更多信息。
要在您的应用程序中使用 Unsplash,请使用如下new
关键字创建一个实例:
import React, { useState } from "react";
import Unsplash, { toJson } from "unsplash-js";
const unsplash = new Unsplash({
accessKey: "your_Access_Key",
});
粘贴您的 UnsplashAccess Key
进行替换your_Access_Key
,您现在可以发出 API 请求。
警告:永远不要共享 API 或任何服务的任何访问密钥或客户端 ID。潜在的不良行为者可能会在互联网上滥用它们。在这种情况下,他们可能会发出异常数量的请求,这些请求可能会被您的服务提供商标记为垃圾邮件,从而停用您的应用程序和帐户。
现在您将创建一个异步函数,该函数将在单击“搜索”按钮时触发。
就在您为 定义状态的位置之后query
,定义一个async
函数:
...
export default function SearchPhotos() {
const [query, setQuery] = useState("");
const searchPhotos = async (e) => {
e.preventDefault();
console.log("Submitting the Form")
};
e.preventDefault()
每当单击“搜索”按钮时,此处都会阻止页面重新加载。您可以onSubmit
在form
标签内的事件中传递此函数。您可以在官方 React 文档中阅读更多相关信息。
...
return (
<>
<form className="form" onSubmit={searchPhotos}>
...
保存文件。现在,如果您单击“搜索”按钮,您将Submitting the Form
在控制台中收到。您可以console.log()
在控制台中成功响应后删除它。
在您的searchPhotos()
函数中,您将使用 Unsplash 实例 ( unsplash
)。您可以使用search
搜索图像的方法。这是语法:
search.photos(keyword, page, per_page, filters)
这是搜索图像的代码;将此代码添加到您的searchPhotos()
函数中:
...
const searchPhotos = async (e) => {
e.preventDefault();
unsplash.search
.photos(query)
.then(toJson)
.then((json) => {
console.log(json);
});
};
...
首先,您使用unsplash.search
然后指定要搜索的内容,在本例中为photos
。我们也可以搜索users
或collections
。photos
将第一个必需参数作为要搜索的关键字,即query
; 您还可以通过可选参数指定页面、每页响应、图像方向等。对于本教程,您只需要page
和per_page
参数,限制从 Unsplash 获得的响应项。
以下是可以提供的所有参数 photos
争论 | 类型 | 选择/必需 | 默认 |
---|---|---|---|
keyword |
细绳 | 必需的 | |
page |
数字 | 可选的 | |
per_page |
数字 | 可选的 | 10 |
filters |
目的 | 可选的 | |
filters.orientation |
细绳 | 可选的 | |
filters.collections |
大批 | 可选的 |
您可以在unsplash-js
GitHub 页面了解有关它们的更多信息。
您使用该toJson
方法将响应转换为 JSON,最后,console.log()
测试 API 请求的响应没有任何错误。您将console .log ()
在接下来的步骤中删除它。
保存文件。现在打开您的控制台并单击“搜索”按钮。你会发现一个像这样的响应 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"
},
...
}
console.log()
当您发现来自 Unsplash API 的成功响应时,您可以删除或注释该语句,这意味着您的代码运行良好。此应用程序将使用该"urls"
字段,因为它将是图像的来源。
您现在已经使用来自用户的查询在使用库单击“搜索”按钮时搜索图像unsplash-js
。接下来,您将响应存储在另一个名为的状态中,pics
并通过映射此状态中的元素来显示图像。
步骤 7 — 在网页上显示图像
在最后一部分中,您将把来自 Unsplash API 的响应存储在另一个名为的状态中pics
,然后映射该状态的元素以在网页上显示图像。
要显示图像,您需要访问响应 JSON,为此,将需要另一个状态。之前的状态query
存储了来自用户的查询,用于向 Unsplash API 发出请求。此状态pics
将存储您从 Unsplash API 获得的图像响应。
在searchPhotos.js
像这样定义另一个状态:
...
const [query, setQuery] = useState("");
const [pics, setPics] = useState([]);
...
此状态已用空数组初始化,所有响应都将作为对象存储在此状态内。换句话说,这是一个对象数组。
要使用 JSON 更新此状态,您将使用setPics
内部unsplash
API 请求:
...
unsplash.search
.photos(query, 1, 20)
.then(toJson)
.then((json) => {
setPics(json.results);
});
...
现在,每次搜索新查询时,此状态都会相应更新。
接下来,创建一个div
与className="card-list"
流向何方后form
标签结束:
...
<button type="submit" className="button">
Search
</button>
</form>
<div className="card-list">
</div>
</>
);
}
在 this 中div
,您将映射状态并显示id
图像:
...
<button type="submit" className="button">
Search
</button>
</form>
<div className="card-list">
{pics.map((pic) => pic.id )}
</div>
</>
);
}
您首先使用{}
传递 JavaScript 表达式,在其中使用状态上的.map()
方法。
保存您的文件。如果你现在搜索,你会看到id
s 与网页上的不同对象相关联:
这很混乱,但这也意味着您的应用程序正在运行。
不是显示pic.id
,而是在map
函数内部打开 JSX并div
使用className="card"
. 这将是每个单独图像的容器:
...
<button type="submit" className="button">
Search
</button>
</form>
<div className="card-list">
{
pics.map((pic) => <div className="card"></div>);
}
</div>
</>
);
}
您现在可以在其中显示图像div
:
...
<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=1080px
。
small
: 非常适合慢速网速,width=400px
.
thumb
:图像的缩略图版本,width=200px
。
在本教程中,您使用的是full
,但您也可以尝试其他类型。您还为图像提供了默认值height
和width
。
保存您的文件。
您的申请即将完成;如果您现在搜索,您将能够看到您的应用程序正在运行。但是还剩下一小行代码。如果您在浏览器中搜索您的图像并转到您的控制台,您将看到一条警告。
Web consoleWarning: Each child in a list should have a unique "key" prop.
To fix this, pass a unique key
to every child using the id
of the image. This key
prop explicitly tells React the identity of each child in a list; this also prevents children from losing state between renders:
...
<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>
</>
);
}
You can adjust the number of images you want to show by passing the corresponding argument to unsplash.search.photos()
.
Save and exit the file. You’ll now have a working photo search app:
In this section, you stored the response from Unsplash API inside the pics
state and displayed the images by mapping over the elements in pics
.
Conclusion
In this tutorial, you developed a React Photo Search app with the Unsplash API. In building the project, the tutorial discussed how to use React Hooks, query an API, and style a user interface.
这个应用程序可以做很多事情来扩展它。例如,您可以添加一个随机按钮来显示随机图像,创建一个复选框以根据用户的偏好在搜索照片或发布照片的用户之间切换,添加无限滚动以显示更多图像等等。您还可以使用相同的概念并制作其他涉及 API 请求的项目,例如Hacker News API。
如果您想查看更多 React 教程,请查看我们的React 主题页面。