react 生命挂钩_如何开始使用React-基于现代项目的初学者指南(包括挂钩)

react 生命挂钩

So you want to start learning React, eh? Then you've come to the right place. This guide will walk you through everything you need to know when getting started with React.

所以您想开始学习React,是吗? 然后您来对地方了。 本指南将引导您完成React入门时需要了解的所有内容。

We'll get set up, explain the "hows and whys" behind the basic concepts, and build a small project which pulls data from an API so we can see everything in action.

我们将进行设置,解释基本概念背后的“方式和原因”,并建立一个小项目,该项目从API提取数据,以便我们可以看到所有发生的事情。

This will be a long one, so skip/re-read sections as you need using the "Jump to Section" links below. With that out of the way, grab a drink, buckle up, and let's get started.

这将是很长的内容,因此请使用下面的“跳至部分”链接根据需要跳过/重新阅读部分。 有了这些,就去喝一杯,系好安全带,然后开始吧。

喜欢视频教程吗? (Prefer Video Tutorials?)

You can check out the YouTube tutorial for this article here.

您可以在此处查看本文YouTube教程。

跳到部分 (Jump to Section)

先决条件 (Prerequisites)

You don't need to know any React before reading this guide. But there are a few things you will need to be familiar with if you want to get the most out of this React guide:

阅读本指南之前,您不需要了解任何React。 但是,如果您想从本React指南中获得最大收益,则需要熟悉以下几点:

基本JavaScript (Basic JavaScript)

React is a JavaScript library, so it makes sense to know JavaScript before learning React, right? Don't worry, you won't need to know JavaScript inside out — you only need to know the basics:

React是一个JavaScript库,因此在学习React之前先了解JavaScript是对的吗? 不用担心,您不需要完全了解JavaScript,只需了解以下基本知识即可:

  • Variables, functions, data types

    变量,函数,数据类型
  • Arrays and Objects

    数组和对象
  • ES6 Syntax (using let & const, Arrow Functions, Destructuring Assignment, classes, importing/exporting, etc)

    ES6语法(使用let&const,箭头功能,解构分配,类,导入/导出等)
  • How JavaScript is used to manipulate the DOM

    如何使用JavaScript操纵DOM

基本HTML (Basic HTML)

In React, we use what's called JSX to create the HTML for our webpages. We'll explain JSX in depth later, but for now make sure you have a good foundation when it comes to HTML:

在React中,我们使用所谓的JSX为我们的网页创建HTML。 稍后我们将深入解释JSX,但现在确保在HTML方面有一个良好的基础:

  • How to structure HTML (how to nest elements and so on)

    如何构造HTML(如何嵌套元素等)
  • HTML attributes (like "id", "class", "onclick" and so on)

    HTML属性(例如“ id”,“ class”,“ onclick”等)

Need some JavaScript review? Subscribe to get my latest book "React-Ready JavaScript" which will help you get ramped up on the JavaScript you need before getting started with React!

需要一些JavaScript评论吗? 订阅以获得我的最新书籍“ React-Ready JavaScript”,这将帮助您在开始使用React之前获得所需JavaScript!

开发环境 (Development Environment)

The first thing we're going to do is set up a development environment. If you've already setup Node.js and installed Visual Studio Code (or your preferred IDE), you can go ahead and skip to the next section.

我们要做的第一件事是设置开发环境。 如果您已经设置了Node.js并安装了Visual Studio Code (或您的首选IDE),则可以继续并跳至下一部分。

Node.js (Node.js)

Go here and download the right package for your OS (Mac/windows etc)

转到此处,为您的操作系统下载正确的软件包(Mac / Windows等)

When the installation completes, open a terminal and type this command:

安装完成后,打开终端并输入以下命令:

node -v

This should show output the version of Node you just installed:

这应该显示输出您刚安装的Node的版本:

This means that the node command works and node has installed successfully — hurray! If you see any errors, try reinstalling Node from the package you downloaded and retry the command again.

这意味着node命令有效并且node已成功安装-哇! 如果看到任何错误,请尝试从下载的软件包中重新安装Node,然后再次重试该命令。

Visual Studio程式码 (Visual Studio Code)

Visual Studio Code is a popular open-source IDE that works well for frontend development. There are a bunch of others you can try — see what your favourite is and download that if you prefer. For now, we'll run with VS Code.

Visual Studio Code是一种流行的开源IDE,非常适合前端开发。 您可以尝试其他方法-查看您最喜欢的是什么,然后根据需要下载。 现在,我们将使用VS Code运行。

Click here and download the version for your platform:

单击此处,下载适用于您平台的版本:

Follow the installation steps, and you should be good to go. Go ahead and fire up Visual Studio Code.

按照安装步骤进行操作,您应该一切顺利。 继续并启动Visual Studio代码。

That's enough development setup for now. There are other nice things you can install (VS Code extensions etc) but we don't need those right now —We're here to learn React!

到目前为止,这已经足够了开发设置。 您还可以安装其他一些不错的东西(VS Code扩展等),但是我们现在不需要这些了-我们在这里学习React!

创建一个React应用 (Creating a React App)

The next step is to create a React project. Lucky for us, the fine folk at Facebook have made this really simple. All we have to do is run a command within our terminal:

下一步是创建一个React项目。 对我们来说幸运的是,Facebook的好人使这变得非常简单。 我们要做的就是在终端中运行命令:

npx create-react-app my-app

This creates a project for us called "my-app" and sets everything up automatically. Pretty cool.

这会为我们创建一个名为“ my-app”的项目,并自动设置所有内容。 很酷

Go ahead and open up a terminal in the directory you want to create your app, e.g. a "projects" folder, and run the command. Let the terminal do its thing, and after a while, this will complete and show you some commands:

继续并在要创建应用程序的目录(例如“ projects”文件夹)中打开一个终端,然后运行命令。 让终端执行其操作,一段时间后,这将完成并显示一些命令:

Notice the create-react-app output has told us what we need to do to start the app. Go ahead and run the commands in your terminal:

注意create-react-app输出已经告诉我们启动应用程序需要做的事情。 继续并在终端中运行命令:

cd my-app
yarn start

This will start a development server and open up a web browser for you:

这将启动开发服务器并为您打开Web浏览器:

You've just set up your first React App! If you want to learn more about what's going on, (check out the "create-react-app" GitHub:)[https://github.com/facebook/create-react-app]

您刚刚设置了第一个React App! 如果您想详细了解正在发生的事情,(请查看“ create-react-app” GitHub:)[ https://github.com/facebook/create-react-app ]

探索创建React应用 (Exploring Create React App)

Open up Visual Studio code (or whatever IDE you installed) and select File > Open… and select the my-app folder that was just created for us using create-react-app. This will open up our shiny new react app in the IDE, so we can write some code!

打开Visual Studio代码(或安装的任何IDE),然后选择“ 文件”>“打开...”,然后选择使用create-react-app为我们创建my-app文件夹。 这将在IDE中打开我们闪亮的新react应用程序,因此我们可以编写一些代码!

You should see the project structure to the right:

您应该在右侧看到项目结构:

Look at all that stuff! Don’t worry too much about a lot of it, it’s mostly boilerplate code and config that we won’t be touching too much in this tutorial — phew! However since you’re a curious developer, let’s have a look at the project tree and see what we have:

看所有这些东西! 不必担心太多,它主要是样板代码和配置,在本教程中我们不会过多涉及-! 但是,由于您是一个好奇的开发人员,所以让我们看一下项目树 ,看看我们拥有什么:

节点模块 (Node Modules)

This is where our packages go that we install through NPM (Node Package Manager). If you’re not familiar with NPM, it’s a glorious place where we can share code (usually open source) that other developers can use instead of writing their own.

这是我们通过NPM(节点程序包管理器)安装的程序包所在的位置。 如果您不熟悉NPM,那么这是一个光荣的地方,我们可以共享其他开发人员可以使用的代码(通常是开源的),而不必编写自己的代码。

Instead of using script tags like we do in traditional HTML, we install these modules as part of the application. Then, we use an import statement to access the code from that module. We’ll see this in action later.

与其像传统HTML中那样使用脚本标签 ,不如将这些模块安装为应用程序的一部分。 然后,我们使用import语句从该模块访问代码。 我们稍后会看到它的作用。

公用资料夹 (Public Folder)

This is where our bundled code goes. When we are ready to deploy our app, we run a ** build script**and the final files go in here. This will typically be our HTML, JavaScript, and CSS files. This is the folder we dump onto a web server somewhere, so that we can let users see our app via a URL

这是我们捆绑的代码的去向。 准备好部署我们的应用程序时,我们将运行**构建脚本**,最终文件将放在此处。 这通常是我们HTML,JavaScript和CSS文件。 这是我们转储到某个地方的Web服务器上的文件夹,以便我们可以让用户通过URL查看我们的应用程序

Index.html (Index.html)

The index.html is the entry point, or the first thing the web browser loads when a user navigates to the URL hosting our app.

index.html是入口点,或者是用户导航到托管我们应用程序的URL时网络浏览器加载的第一件事。

If we look at the file, it’s a just a normal HTML file with normal HTML stuff that you will hopefully be familiar with. If we look at the body — it’s empty. React will dynamically convert our React code into HTML and load it here, in the “root” div.

如果我们看一下该文件,那只是一个普通HTML文件,其中包含您可能会熟悉的普通HTML内容。 如果我们看看身体-它是空的。 React会将我们的React代码动态地转换为HTML并将其加载到“ root” div中。

With that out of the way, let’s look at the juicy parts — the code.

顺便说一句,让我们看一下多汁的部分-代码。

我们的第一个组成部分 (Our First Component)

Open up App.js from the project tree. This is the Main component in our application. This is the first component to get rendered. It’s the “big cheese” of components.

从项目树中打开App.js。 这是我们应用程序中的主要组件。 这是第一个被渲染的组件。 这是组件的“大奶酪”。

The first thing we’re going to do in our big cheese component is delete everything, and build our very own component from scratch, to better understand what’s going on.

我们在大型奶酪组件中要做的第一件事是删除所有内容,并从头开始构建我们自己的组件,以更好地了解正在发生的事情。

Now that we have a nice blank slate to play with we will start by importing react. This brings the React library into scope and gives us access to all the lovely features:

现在我们有了一个不错的空白选择,我们将从导入react开始。 这将React库带入了范围 ,并使我们能够访问所有可爱的功能:

import React from "react";

Next we will declare a function. We’ll use ES6 arrow functions here. That’s more or less what a “component” is — a function with some logic and markup. We’re also going to export this function so we can use it elsewhere:

接下来,我们将声明一个函数。 我们将在此处使用ES6箭头功能。 这或多或少是一个“组件”的含义-一个具有一定逻辑和标记的函数。 我们还将导出此函数,以便可以在其他地方使用它:

const App = () => {

}

export default App;

Within our function we want to write return(). This is what get’s returned from this component, and contains our markup which gets converted and rendered as HTML.

在我们的函数中,我们要编写return() 。 这是从该组件返回的内容,其中包含我们的标记,该标记被转换并呈现​​为HTML。

Finally let’s add a <div> with a <h1> title tag. Our finished component looks like this:

最后,让我们添加带有<h1>标题标签的<div> 。 我们完成的组件如下所示:

import React from "react";

const App = () => {
  return (
    <div>
       <h1>Hello React World</h1>
       <h2>
             This is our first React App - isn't it marvellous?!
       </h2>
    </div>
  );
}

export default App;

Now you’re probably thinking, "Woah! HTML in a function? What is this madness?" Even though it looks like HTML, it’s actually something called JSX (JavaScript XML). This basically allows us to mix JavaScript and HTML together.

现在您可能在想,“哇!函数中HTML?这是什么疯狂?” 即使看起来像HTML,它实际上也叫做JSX(JavaScript XML) 。 基本上,这使我们可以将JavaScript和HTML混合在一起。

This might seem a bit strange. We originally learned front end development by separating our HTML and JavaScript (and even CSS). Yet JavaScript and the way we design apps has evolved, and keeping everything together in the same “component” makes it easier to maintain and reuse our code.

这似乎有点奇怪。 我们最初是通过分离HTML和JavaScript(甚至CSS)来学习前端开发的。 但是JavaScript和我们设计应用程序的方式已经发生了发展,将所有内容都放在同一个“组件”中使维护和重用我们的代码变得更加容易。

Let’s see this in action. Open your terminal and run

让我们来看看实际情况。 打开终端并运行

npm start

This should open the browser and you should see the app running.

这应该打开浏览器,您应该看到该应用程序正在运行。

Congrats! You’ve just created your first component!

恭喜! 您刚刚创建了第一个组件!

JSX (JSX)

You probably have some question marks floating above your head when thinking about this JSX thing. Let’s take a deeper look into this.

考虑到JSX时,您可能会在脑海中浮现一些问号。 让我们更深入地研究一下。

return (
    <div>
      <h1>Hello React World</h1>
      <h2>
          This is our first React App - isn't it marvellous?!
      </h2>
    </div>
  );

This looks like HTML, but it’s not. This is JSX! Even though it looks like normal HTML, what’s happening behind the scenes is that React is creating the element tree, using this syntax:

看起来像HTML,但不是。 这是JSX ! 即使看起来像普通HTML,幕后发生的事情是React正在使用以下语法创建元素树

React.createElement(component, props, ...children)
  • component: The HTML element you wish to created, i.e. h1, div etc

    组件:您要创建的HTML元素 ,即h1div

  • props: any props you wish to pass to that component (we’ll talk about props later)

    道具:您希望传递给该组件的任何props (我们稍后将讨论道具)

  • children: An array of HTML elements that are nested within this element

    元素 :嵌套在此元素内HTML元素数组

So, the same component we have just created can be written as so:

因此,我们刚刚创建的相同组件可以这样写:

const App = () => {
  return (
    React.createElement(
      "div",
      null,
      React.createElement("h1", null, "Hello React World"),
      React.createElement(
        "h2",
        null,
        "This is our first React App - isn't it marvellous?!"
      )
    )
  );
}

Which looks a bit nasty (it was even nastier trying to type it out). If you trace through it carefully, you can see we are creating a div element, which has no props (indicated by passing null as a second argument). Lastly we are creating 2 more elements using the createElement syntax — our H1 and our H2 elements.

看起来有点令人讨厌(试图输入它甚至更讨厌)。 如果仔细地跟踪它,您会看到我们正在创建一个div元素,该元素没有道具(通过将null作为第二个参数传递来指示)。 最后,我们正在创建使用2种元素createElement语法-我们的H1和我们的H2元素。

If you’ve been playing with JavaScript for a while, you might have noticed that this is similar to document.createElement. And it is! This is a JavaScript library after all!

如果您使用JavaScript已有一段时间,您可能已经注意到它类似于document.createElement 。 是的! 毕竟这是一个JavaScript库!

This is the advantage of JSX in React — it lets us write HTML like syntax, without the messy React.createElement() stuff.

这是JSX在React中的优势-它使我们可以编写类似于语法HTML,而无需凌乱的React.createElement()东西。

In the real world, React developers almost exclusively use JSX to write their code. No, this section wasn’t a waste of time — it’s always good to understand what happens under the hood. Knowledge is power (and less questions in my inbox)!

在现实世界中,React开发人员几乎完全使用JSX编写代码。 不,这部分不是浪费时间-了解幕后发生的事情总是很好。 知识就是力量(收件箱中的问题更少)!

使事物充满活力 (Making things dynamic)

So we’ve seen JSX, and gotten over our fear of it (hopefully). But what’s the point? Why use this JSX thing, when we could just use HTML? They look the same? Right?

因此,我们已经了解了JSX,并克服了对它的恐惧(希望如此)。 但是有什么意义呢? 当我们只能使用HTML时,为什么还要使用这种JSX呢? 他们看起来一样吗? 对?

Good question my friend! Well, if we remember what JSX stands for — JavaScript XML. This means we can use JavaScript to make things dynamic. Our previous example looks like so:

好问题,我的朋友! 好吧,如果我们还记得JSX的意思,那就是JavaScript XML。 这意味着我们可以使用JavaScript使事物动态化。 我们之前的示例如下所示:

const App = () => {
  return (
    <div>
      <h1>Hello React World</h1>
      <h2>This is our first React App - isn't it marvellous?!</h2>
    </div>
  );
}

Now let’s say we want to make our text more dynamic. Firstly let’s add a variable to hold our message:

现在,我们要使文本更具动态性。 首先,让我们添加一个变量来保存我们的消息:

cont message = "This is my first variable rendered in JSX!"

cont message = "This is my first variable rendered in JSX!"

Now to add JavaScript to this, we use ** curly braces**:

现在向其中添加JavaScript,我们使用**花括号**:

const App = () => {
  const message = "This is my first variable rendered in JSX!";

  return (
    <div>
      <h1>Hello React World</h1>
      <h2>{message}</h2>
    </div>
  );
}

If you run this in the browser, you’ll notice the text of our message variable appears. Go ahead and change the message variable text to something else and watch the magic happen.

如果在浏览器中运行此命令,则会注意到出现了message变量的文本。 继续,将消息变量文本更改为其他内容,然后观察魔术的发生。

We use curly braces to tell the compiler “execute this code as JavaScript”. If we didn’t have curly braces, the message variable wouldn't get executed as JavaScript and instead, the text “message” would appear on the screen. Try this out and see!

我们使用花括号告诉编译器“将这些代码作为JavaScript执行 ”。 如果我们没有大括号,则message变量将不会作为JavaScript执行,而是在屏幕上显示文本“ message”。 试试看,看看!

处理事件 (Handling Events)

The same approach can be taken when with handling events. When using JSX, React gives us access to event listeners you may already be familiar with: onClick, onPress, onSubmit and so on.

处理事件时可以采用相同的方法。 使用JSX时,React使我们可以访问您可能已经熟悉的事件侦听器onClickonPressonSubmit等。

Let’s say we want to display an alert when the message is clicked. Firstly, we add the onClick property to our h2 tag.

假设我们要在单击消息时显示警报。 首先,我们将onClick属性添加到我们的h2标签中。

The onClick property accepts a function (in other words, we pass a function as an argument. This function will call the alert like so:

onClick属性接受一个函数(换句话说,我们将一个函数作为参数传递。该函数将如下调用警报:

const App = () => {
  const message = "This is my first variable rendered in JSX!";  

  return (
    <div>
      <h1>Hello React World</h1>
      <h2 onClick={()=> alert("you clicked the message!")}>{message}</h2>
    </div>
  );
}

Notice how we use a arrow function here to create a nice, concise inline function. If you’re not familiar with this syntax, make sure to checkout my book where I cover this and more here.

请注意,我们在此处如何使用箭头函数创建漂亮,简洁的内联函数。 如果您不熟悉此语法,请确保在有关本书的更多地方查阅我的书

Again, notice how we have put this code within curly braces, to ensure the function gets executed as JavaScript.

再次注意,我们如何将这段代码放在花括号内 ,以确保该函数作为JavaScript执行。

通话功能 (Calling functions)

So we looked at inline functions in the last example. Since JSX is JavaScript, we can create and reference functions outside of the return block. Our last example could look like this:

因此,我们在上一个示例中介绍了内联函数。 由于JSX是JavaScript,因此我们可以在return块之外创建和引用函数。 我们的最后一个示例可能如下所示:

const App = () => {
  const message = "This is my first variable rendered in JSX!";  

  const handleClick = () =>{
	alert("you clicked the message!");
  }

  return (
    <div>
      <h1>Hello React World</h1>
      <h2 onClick={handleClick}>{message}</h2>
    </div>
  );
}

Notice how we created a function called handleClick which alerts the message. Instead of using an inline function, we reference this function in our onClick property. Try this out and see what happens.

注意我们如何创建一个名为handleClick的函数来警告消息。 代替使用内联函数,我们在onClick属性中引用此函数。 试试看,看看会发生什么。

These are just some examples as to how we can use JavaScript to make things dynamic, and hopefully shows you the power of JSX. We’ll deepen our understandings later as we build out an example, so don't worry if some things don’t make sense just yet!

这些只是有关如何使用JavaScript使事物动态化的一些示例,并希望向您展示JSX的强大功能。 稍后我们将通过建立示例来加深我们的理解,所以不要担心某些事情还没有意义!

组件如何渲染 (How a Component gets Rendered)

Hopefully I’ve cleared up some of the questions you might have around JSX. The next thing you might be wondering is — how does a component get rendered? Where? When?

希望我已经解决了您可能对JSX提出的一些问题。 您可能想知道的下一件事是-如何呈现组件? 哪里? 什么时候?

Let’s start at the beginning. If you look back to our file structure we have an index.js file. This is the first file to run (we often call this an “Entry Point”). This is typically by convention — you can change the entry point if you want, but for now we’ll leave it alone.

让我们从头开始。 如果您回顾我们的文件结构,我们有一个index.js文件。 这是第一个运行的文件(我们通常将其称为“入口点”)。 通常这是惯例,您可以根据需要更改入口点,但现在我们将不理它。

If we dig into the file, you’ll notice we have this line:

如果我们深入研究文件,您会注意到我们有以下一行:

ReactDOM.render(<App />, document.getElementById("root"));

Notice we have document.getElementById(“root”) — finally some normal looking JavaScript! This gets the root element from the DOM using plain ol’ JavaScript, and renders our App Component within it. Our App component is imported like so:

注意,我们有document.getElementById(“root”) -最后是一些看起来正常JavaScript! 这将使用普通JavaScript从DOM中获取元素,并在其中呈现我们的App组件。 我们的App组件是这样导入的:

import App from "./App"

Remember we exported our app component in App.js. This lets other files/components import and use our App component.

请记住,我们在App.js中导出了我们的应用程序组件。 这使其他文件/组件可以导入和使用我们的App组件。

So where does the root element come from? Well, remember our index.html file in the public folder? This index.html file is the first HTML file to get loaded when the website loads

那么元素从何而来? 好吧,还记得我们公用文件夹中的index.html文件吗? 该index.html文件是网站加载时第一个加载HTML文件

Within it we have a div with an ID of root, which is empty. This is where React loads our components. Let’s have a look at this in the dev tools.

其中有一个ID为rootdiv ,它为空。 这是React加载我们组件的地方。 让我们在开发工具中查看一下。

Open up Chrome (or whatever browser you use) and inspect the dev tools. You’ll see somewhere in the tree a div with id=“root”, as well as the HTML rendered from our App component. Pretty cool!

打开Chrome(或您使用的任何浏览器)并检查开发工具。 您会在树的某处看到一个id =“ root”div ,以及从我们的App组件呈现HTML 。 太酷了!

快速总结 (Quick Summary)

Before moving on, let’s quickly summarise what we’ve learned so far:

在继续之前,让我们快速总结一下到目前为止所学到的内容:

  • We have an index.html file, which is the skeleton of our web app

    我们有一个index.html文件,这是我们网络应用程序的框架

  • When the app starts, index.html loads, and imports our App Component

    应用启动时, index.html加载并导入我们的应用组件

  • The JSX in the App component get’s converted to HTML, which is then rendered in the index.html file at the root div

    将App组件中的JSX转换为HTML,然后将其呈现在根divindex.html文件中

让我们建立一个联系人列表! (Lets Build a Contacts List!)

Now that we have our feet wet with React, and have a better understanding of how things fit together, let’s build an example application using what we have learned so far. We’ll also learn some common React features that will help you well on to the road to getting started with React. Let’s go!

既然我们已经开始使用React了,并且对事物如何融合有了更好的了解,那么让我们使用到目前为止所学的知识来构建一个示例应用程序。 我们还将学习一些常见的React功能,这些功能将帮助您更好地开始使用React。 我们走吧!

Our contacts list will display a number of a contacts, including their name, email, age and avatar (or, profile image). We’ll build this up gradually, eventually pulling data from an API. How exciting!

我们的联系人列表将显示一些联系人,包括他们的姓名,电子邮件,年龄和头像(或个人资料图片)。 我们将逐步进行构建,最终从API中提取数据。 多么激动人心!

获取样式 (Get the styles)

Since this is a React tutorial, we’re going to focus on the inner workings of React and not worry about creating nice styles. In your source folder, create a new file styles.css and paste in the following code:

因为这是一个React教程,所以我们将专注于React的内部工作原理,而不用担心创建漂亮的样式。 在您的源文件夹中,创建一个新文件styles.css并粘贴以下代码:

.contact-card {
  display: flex;
  padding: 10px;
  color: #ffffff;
  background-color: rgb(42, 84, 104);
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  box-shadow: 10px 10px 25px -16px rgba(0, 0, 0, 0.75);
  border-radius: 10px;
  max-width: 500px;
  max-height: 125px;
  margin-bottom: 10px;
}

.contact-card p {
  margin-left: 10px;
  margin-top: 0;
}

button {
  margin-left: 10px;
  margin-bottom: 10px;
}

Next, go into App.js and import the stylesheet like so:

接下来,进入App.js并导入样式表,如下所示:

import "./styles.css";

创建联系卡 (Creating the Contact Card)

While we’re still in App.js, let’s add the basic JSX to get our layout for the contact card in place. Remove everything from the return statement and add the following:

当我们仍然在App.js中时 ,让我们添加基本的JSX来使名片的布局到位。 从return语句中删除所有内容,并添加以下内容:

<div className="contact-card">
	<img src="https://via.placeholder.com/150" alt="profile" />
	<div className="user-details">
		<p>Name: Jenny Han</p>
		<p>Email: Jenny.Han@notreal.com</p>
		<p>Age: 25</p>
	</div>
</div>

All we’re doing here is creating a div to “wrap” the contact card details, adding an image (the image will use a placeholder taken from the web for now), and adding a few p tags to hold the details we need in the contact card. Finally we’re adding some CSS classes taken from styles.css;

我们在这里要做的就是创建一个div来“包装”联系人卡片的详细信息,添加一张图片(该图片现在将使用从网络上获取的占位符),并添加一些p标签来保存我们需要的详细信息联系人卡。 最后,我们添加了一些来自styles.css CSS类

NOTE: to reference CSS classes, we need to use the className keyword. This is because we are writing JSX, and “class” is a reserved word in JavaScript.

注意:要引用CSS类,我们需要使用className关键字。 这是因为我们正在编写JSX,而“ class”是JavaScript中的保留字。

Here’s what we have so far in our App.js file:

到目前为止,我们的App.js文件中包含以下内容:

import React from "react";
import "./styles.css";

const App = () => {
  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile" />
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        <p>Age: 25</p>
      </div>
    </div>
  );
}

If you run this in the browser, you should see something similar to the following:

如果在浏览器中运行此程序,则应该看到类似以下内容的内容:

使我们的联系卡可重复使用 (Making our Contact Card Reusable)

OK so we have our contact card! However it’s not very reusable. We know that we are going to need to reuse this code if we want to render more than one card, so it makes sense to break this out into it’s own component

好的,所以我们有我们的联系卡! 但是,它不是很可重用。 我们知道,如果要渲染多个卡,将需要重用此代码 ,因此有必要将其分解为自己的组件

NOTE — To make it easier to follow, I am going to a put all the components we make into App.js . In the real world it would be better to split these different components into their own files, and import/export them where appropriate.

注意—为了更容易理解,我将把我们制造的所有组件放入App.js中 。 在现实世界中,最好将这些不同的组件拆分成各自的文件,并在适当的地方导入/导出它们。

Just beneath the App function, create a new function called ContactCard, and copy the JSX from App to ContactCard like so:

App函数下方,创建一个名为ContactCard的新函数,然后将JSX从App复制到ContactCard,如下所示:

const ContactCard = () => {
  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile" />
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        <p>Age: 25</p>
      </div>
    </div>
  );
};

Again, a component in React is just a function that returns some JSX. Now that we’ve moved our JSX to the ContactCard we can use this component within our main App component:

同样,React中的组件只是一个返回JSX函数 。 现在,我们已经将JSX移到了ContactCard,我们可以在主要的App组件中使用该组件

const App = () => {
  return (
    <>
      <ContactCard />
    </>
  );
}

We use our own components like any old HTML/JSX tag. We just put the name of our component in angle brackets. Our App.js file should look like this:

我们使用自己的组件,就像所有旧HTML / JSX标签一样。 我们只是将组件名称放在尖括号中。 我们的App.js文件应如下所示:

// App.js
import React from "react";
import "./styles.css";

const App = () => {
  return (
    <>
      <ContactCard />
    </>
  );
};

const ContactCard = () => {
  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile" />
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        <p>Age: 25</p>
      </div>
    </div>
  );
};

Now if you run this in the browser, things will look the same as they did before — which is what we want. We now have a ContactCard component that we can use as many times as we like:

现在,如果您在浏览器中运行此程序,则其外观将与以前一样,这就是我们想要的。 现在,我们有了一个ContactCard组件,我们可以随意使用它多次:

const App = () => {
  return (
    <>
      <ContactCard />
      <ContactCard />
      <ContactCard />
    </>
  );
};

Update the App component to include another 2 ContactCard components. The above example will render 3 contact cards in the browser. Go and check it out!

更新App组件以包括另外2个ContactCard组件。 上面的示例将在浏览器中呈现3个联系人卡片。 去看看吧!

Think of this like a “stamp” on the page. Every ContactCard component we add is another “stamp” and renders the same markup on the page

将此视为页面上的“戳记”。 我们添加的每个ContactCard组件都是另一个“邮票”,并在页面上呈现相同的标记

让我们谈谈状态-useState Hook (Let’s talk about State — the useState Hook)

If you’ve been getting started with React already, you may have heard of the term state. State is quite a big deal in React. So what is it?

如果您已经开始使用React,那么您可能听说过状态state 。 在React中,状态非常重要。 那是什么

State is basically an object that represents a part of an app that can change, which the UI “reacts” to. State can be anything; objects, booleans, arrays, strings or integers

状态基本上是一个对象,代表可以更改的应用程序的一部分,UI会对其进行响应。 国家可以是任何事物; 对象,布尔值,数组,字符串或整数

Let’s take an example.

让我们举个例子。

Some people who appear in our contact list are shy and do not want their age being displayed until a button is clicked. We can store whether the age should be shown or not in state by using the useState hook within the component. Which looks like this:

出现在我们的联系人列表中的某些人很害羞,不希望在单击按钮之前显示年龄。 通过使用组件内的useState挂钩,我们可以存储是否应显示年龄 。 看起来像这样:

const [showAge, setShowAge] = useState(false);

“What the hell is going on here?” Let me explain.

“这到底是怎么回事?” 让我解释。

The useState object gives us a variable with the current value, and a function that lets us change that value. When we call useState we can define an initialvalue (in this case, false).

useState对象为我们提供了具有当前值的变量,以及使我们能够更改该值的函数 。 当我们调用useState时,我们可以定义一个初始值(在这种情况下,为false )。

We use destructuring assignment on the useState hook to get these. You don’t have to worry about destructuring assignment right now, just remember that the first variable lets us access the state value, the second one lets us change it.

我们在useState挂钩上使用解构分配来获取这些。 您现在不必担心会破坏分配,只需记住第一个变量可以让我们访问状态值,第二个变量可以让我们更改状态值。

Go ahead and add the above code snippet to the ContactCard component like so:

继续,将以上代码片段添加到ContactCard组件中,如下所示:

const ContactCard = () => {
  const [showAge, setShowAge] = useState(false);

  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile" />
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        <p>Age: 25</p>
      </div>
    </div>
  );
};

Now we have a state object, how do we use it? Well, we can reference the showAge variable like any other variable. In this case, we want to _only show the age if the showAge variable is true.

现在我们有了一个状态对象,我们该如何使用它? 好吧,我们可以像其他任何变量一样引用showAge变量。 在这种情况下,如果showAge变量为true ,我们只想显示年龄。

We can do this using the ternary operator :

我们可以使用三元运算符来做到这一点:

{showAge === true ? <p>Age: 25</p> : null}

This example reads as if the showAge variable is true, render the age, if not, render nothing.

该示例读取的内容似乎是showAge变量为true,呈现年龄,否则,不呈现任何内容

Go ahead and add this to the ContactCard component, like so:

继续并将其添加到ContactCard组件,如下所示:

const ContactCard = () => {
  const [showAge, setShowAge] = useState(false);

  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile" />
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        {showAge === true ? <p>Age: 25</p> : null}
      </div>
    </div>
  );
};

Now, if you run the app in the browser, you’ll see the age disappears — that’s because our showAge variable has been initialised with false. If we initialise our showAge variable with true:

现在,如果您在浏览器中运行该应用程序,您会看到年龄消失了-这是因为我们的showAge变量已使用false初始化。 如果我们使用true初始化showAge变量:

const [showAge, setShowAge] = useState(true);

The age will appear on the contact card. Nice! Although, its not great — we don’t want to change the code whenever we want to show the age on the contact card!

年龄将显示在联系卡上。 真好! 虽然效果不佳-我们不想在要显示联系卡上的年龄时更改密码!

Before we look at how to dynamically change our showAge variable, lets tidy the code a bit. Go ahead and replace this line:

在研究如何动态更改showAge变量之前,让我们整理一下代码。 继续并替换此行:

{showAge === true ? <p>Age: 25</p> : null}

With:

带有:

{showAge && <p>Age: 25</p> }

This gives the same result, just in a more concise way.

这只是以更简洁的方式给出了相同的结果。

TIP: Shorten code where it makes sense to, don’t feel like you have to shorten every line of code you write! Readability should come first.

提示:在需要的地方缩短代码,不必觉得您必须缩短编写的每一行代码! 可读性应该放在首位。

更新状态 (Updating State)

Ok back to updating state. If we remember back, the useState() hook gives us a function to update the state. Let’s wire this up to a button, which, when clicked, will toggle showing the age on the contact card.

确定回到更新状态。 如果我们还记得的话, useState()挂钩为我们提供了一个更新状态函数 。 让我们将其连接到一个按钮,单击该按钮将切换显示联系人卡片上的年龄。

We can do this with the following:

我们可以执行以下操作:

<button onClick={() => setShowAge(!showAge)}>
	Toggle Age 
</button>

What this is doing is calling the setShowAge function (which we get from the useState hook) to change the value of show age to the opposite of what it currently is.

这是在调用setShowAge函数 (我们从useState挂钩获得),将show age更改为当前值的相反值

NOTE: I’m using the Arrow Function syntax here to pass a function to the onClick property. If you’re not familiar we this, a quick reminder that you can get my [book where I discuss the important bits of JavaScript to know before React here].

注意:我在这里使用箭头函数语法将函数传递给onClick属性。 如果您对我们不熟悉,可以快速提醒您:[您可以在此本书中讨论在React之前需要了解JavaScript的重要知识]。

When the state updates, React will re-render the component and since the value of showAge is true, the age will be displayed.

状态更新时,React将重新渲染组件,并且由于showAge值为true,因此将显示年龄。

If the user clicks the button again, this will set showAge to false, React will re-render the component, and the age will be hidden:

如果用户再次单击按钮,这会将showAge设置为false ,React将重新渲染组件,并且年龄将被隐藏:

Look at our fancy toggle in action!

看看我们花哨的动作吧!

TIP: Whenever the components state changes, React will re-render the component with the new state

提示:每当组件状态更改时,React都会使用新状态重新渲染组件

Notice how even though we have 3 ContactCard components being rendered, when we click the button the age only displays for one of the cards, and not all of them. This is because state belongs to the individual component. In other words, each ContactCard component that renders is a copy, and has its own state/data.

请注意,即使渲染了3个ContactCard组件,单击按钮时,年龄也只会显示其中一张卡,而不会显示所有卡。 这是因为状态属于各个组成部分 。 换句话说,每个呈现的ContactCard组件都是一个copy ,并且具有自己的状态/数据。

道具介绍 (Introducing Props)

So now we have a lovely new ContactCard component that we’re reusing a few times. Although its not really reusable, since the name, email, age and avatar are the same for each of our components. Oh dear! We can make this data more dynamic with what are called props.

因此,现在我们有了一个可爱的新ContactCard组件,我们将对其重复使用几次。 尽管它并不是真正可重用的,但由于我们每个组件的名称,电子邮件,年龄和头像都相同。 噢亲爱的! 我们可以使用所谓的props使这些数据更加动态。

Since you’re just getting started with React, you can think ofProps as data that gets passed to a component, which the component can then use. For example, we can pass in our avatar , ** email**, name and age as props to our Contact Card component like so:

由于您刚开始使用React,因此可以将Props视为传递给组件的数据,组件可以使用这些数据。 例如,我们可以将头像 ,**电子邮件**, 姓名年龄作为道具传递给“ 联系卡”组件,如下所示:

<ContactCard
  avatar="https://via.placeholder.com/150"
  name="Jenny Han"
  email="jenny.han@notreal.com"
  age={25}
/>

As you can see, we define a prop by giving it a name. Eg. name and using the equals to assign some value to that prop e.g. Jenny Han.

如您所见,我们通过给道具命名来定义它。 例如。 命名并使用等于给那个道具赋一些值,例如詹妮汉

We can have as many props as we want, and we can name these props whatever we want, so they’re pretty flexible.

我们可以拥有任意数量的道具,并且我们可以根据需要命名这些道具,因此它们非常灵活。

Props can hold different types of data, i.e. strings, numbers, booleans, objects, arrays and so on.

道具可以保存不同类型的数据,即字符串,数字,布尔值,对象,数组等。

NOTE: Props must be defined using quoted text (e.g. name=“Jenny Han”) or within braces (e.g. age={25}. If we leave out the braces for anything other than strings things start to break — age=25 );

注意:必须使用带引号的文本(例如name =“ Jenny Han”)或在花括号内(例如age={25} )来定义道具。如果我们不考虑花括号而不是字符串,则东西开始折断— age=25

Go ahead and replace the current ContactCard components within our App component with the following:

继续,并用以下内容替换App组件中的当前ContactCard组件:

<ContactCard
  avatar="https://via.placeholder.com/150"
  name="Jenny Han"
  email="jenny.han@notreal.com"
  age={25}
/>

<ContactCard
  avatar="https://via.placeholder.com/150"
  name="Jason Long"
  email="jason.long@notreal.com"
  age={45}
/>

<ContactCard
  avatar="https://via.placeholder.com/150"
  name="Peter Pan"
  email="peter.pan@neverland.com"
  age={100}
/>

All we’re doing here is passing the data that the component needs to each component as props. Notice how the data is different for each component.

我们在这里所做的就是将组件所需的数据作为道具传递给每个组件。 注意每个组件的数据如何不同。

在组件内使用道具 (Using Props within a component)

We’ve sent a bunch of props down to the ContactCard component, so let’s tell the ** ContactCard** how to use them.

我们已经向ContactCard组件发送了很多道具,所以让我们来告诉** ContactCard **如何使用它们。

Until now, our ** ContactCard** function doesn’t accept any parameters. React, being the magical thing that it is, automatically puts all our props into a lovely props object, that gets passed into the component:

到目前为止,我们的** ContactCard **函数不接受任何参数 。 React是一种神奇的东西,它会自动将我们所有的props放入一个可爱的props对象 ,该对象会传递到组件中:

const ContactCard = props => {
	//...other code
};

Notice the props variable. This is an object containing the props we defined previously. We can access our defined props by using the dot notation like so:

注意props变量。 这是一个包含我们先前定义的道具的对象。 我们可以使用点符号访问我们定义的道具 ,如下所示:

const ContactCard = props => {
	console.log(props.avatar); 
	console.log(props.name);
	console.log(props.email);
	console.log(props.age);

	//...other code
};

Finally, we want to replace the hardcoded values in our JSX, with the values we receive from the props:

最后,我们想用从props收到的值替换JSX中的硬编码值:

return (
  <div className="contact-card">
    <img src={props.avatar} alt="profile" />
    <div className="user-details">
      <p>Name: {props.name}</p>
      <p>Email: {props.email}</p>
      <button onClick={() => setShowAge(!showAge)}>Toggle Age </button>
      {showAge && <p>Age: {props.age}</p>}
    </div>
  </div>
);

Notice how we have set the image source using whatever value we received from props. We did similar for name, email, and age. Also notice how we wrap this code in curly braces, so it gets executed as JavaScript.

注意我们如何使用从道具获得的任何值设置图像源 。 我们在姓名电子邮件年龄方面做得差不多。 另请注意,我们如何将这些代码花括号中 ,以便将其作为JavaScript执行。

Our final App.js file looks like this:

我们最终的App.js文件如下所示:

// App.js
const App = () => {
  return (
    <>
      <ContactCard
        avatar="https://via.placeholder.com/150"
        name="Jenny Han"
        email="jenny.han@notreal.com"
        age={25}
      />
      <ContactCard
        avatar="https://via.placeholder.com/150"
        name="Jason Long"
        email="jason.long@notreal.com"
        age={45}
      />
      <ContactCard
        avatar="https://via.placeholder.com/150"
        name="Peter Pan"
        email="peter.pan@neverland.com"
        age={100}
      />
    </>
  );
};

const ContactCard = props => {
  const [showAge, setShowAge] = useState(false);

  return (
    <div className="contact-card">
      <img src={props.avatar} alt="profile" />
      <div className="user-details">
        <p>Name: {props.name}</p>
        <p>Email: {props.email}</p>
        <button onClick={() => setShowAge(!showAge)}>
			Toggle Age 
		</button>
        {showAge && <p>Age: {props.age}</p>}
      </div>
    </div>
  );
};

If you run this in the browser, you should see something similar to this:

如果在浏览器中运行此程序,则应该看到类似以下内容:

Hurray! Our component works the same as before, but its now more dynamic. We can reuse the same ContactCard but passing in different data — whilst keeping the layout, styles, and state objects the same.

欢呼! 我们的组件工作原理与以前相同,但是现在更加动态。 我们可以重复使用相同的ContactCard,但传递不同的数据-同时保持布局,样式和状态对象相同。

从列表渲染组件 (Rendering components from a List)

Our contacts list is coming along nicely, we have some well crafted, reusable code so time to leave it alone right? Wrong! Let’s take it a step further.

我们的联系人列表进展顺利,我们有一些精心设计,可重用的代码,因此有时间单独处理吧? 错误! 让我们更进一步。

In a real application, data usually comes in the form of an array of data, e.g. after an API call. Let’s pretend we’ve made an API call to retrieve some users from a database and have received the following data:

在实际应用中,数据通常以数据数组的形式出现,例如在API调用之后。 假设我们已经进行了API调用,以从数据库中检索一些用户,并收到了以下数据:

const contacts = [
    { name: "Jenny Han", email: "jenny.han@notreal.com", age: 25 },
    { name: "Jason Long", email: "jason.long@notreal.com", age: 45 },
    { name: "Peter Pan", email: "peter.pan@neverland.com", age: 100 }
];

Paste this into the App() component at the top of the function. The eagled eye amongst you will notice how this data is similar to what we already have. But how we we turn this data into ContactCard components? Well, remember all those days you spent learning how to loop over an array using .map()? Now is the day we put that into action!

将此粘贴到函数顶部的App()组件中。 你们当中的鹰眼将注意到此数据与我们已经拥有的数据有何相似之处。 但是我们如何将这些数据转换为ContactCard组件? 好吧,还记得那些花时间学习如何使用.map()遍历数组的日子吗? 现在是我们付诸行动的一天!

To display a list of components, we:

要显示组件列表,我们:

  1. Loop over the array using .map()

    使用.map()遍历数组

  2. For each item in the array, create a new ContactCard component

    对于数组中的每个项目,创建一个新的ContactCard组件

  3. Pass the data from each object in the array to the ContactCard component as props

    将数据从数组中的每个对象传递给ContactCard组件作为道具

Let’s see how this works. In our appApp() component, replace the return statement with this:

让我们看看它是如何工作的。 在我们的应用程序App()组件中,将return语句替换为:

return (
  <>
    {contacts.map(contact => (
      <ContactCard
        avatar="https://via.placeholder.com/150"
        name={contact.name}
        email={contact.email}
        age={contact.age}
      />
    ))}
  </>
);

As you can see, we map over the array. For each object in the array, we want to create a new ContactCard component. For the props, we want to take the name, email, and age from the current object the map function is on. In other words, from the contact variable.

如您所见,我们映射到array 。 对于数组中的每个对象,我们要创建一个新的ContactCard组件。 对于道具,我们要从地图功能所在当前对象中获取名称电子邮件地址年龄 。 换句话说,来自contact变量。

NOTE: I’ve left the “avatar” prop alone, as this is the same for now — it’ll change later in the tutorial

注意:我已经单独留下了“头像”道具,因为现在这是一样的—它会在本教程的后面进行更改

And that’s it! Our App.js file looks like this:

就是这样! 我们的App.js文件如下所示:

//App.js
const App = () => {
  const contacts = [
    { name: "Jenny Han", email: "jenny.han@notreal.com", age: 25 },
    { name: "Jason Long", email: "jason.long@notreal.com", age: 45 },
    { name: "Peter Pan", email: "peter.pan@neverland.com", age: 100 },
    { name: "Amy McDonald", email: "amy@email.com", age: 33 }
  ];

  return (
    <>
      {contacts.map(contact => (
        <ContactCard
          avatar="https://via.placeholder.com/150"
          name={contact.name}
          email={contact.email}
          age={contact.age}
        />
      ))}
    </>
  );
};

Run this in the browser and things should look the same. We haven’t changed our ContactCard, merely changed where we got the data from. The cool thing about this is that if you added another row to the contacts array, the extra component will get rendered automatically — you don’t have to do anything else! Try this for yourself and see.

在浏览器中运行它,外观应该相同。 我们没有更改ContactCard ,只是更改了从中获取数据的位置。 很棒的事情是,如果您在通讯录数组中添加了另一行,多余的组件将自动呈现-您无需执行其他任何操作! 自己尝试一下,看看吧。

从API提取数据 (Pulling data from an API)

We’ve got a nice looking React App now. It's dynamic and things are working well. Which is a good place to be since we’re just getting started with React! But there are some tidy ups we need to make. In a real application, data will be pulled in from an API.

我们现在有一个外观漂亮的React App。 它是动态的,并且运行良好。 因为我们才刚刚开始使用React,所以这是一个好地方! 但是,我们需要进行一些整理。 在实际的应用程序中, 将从API提取数据

For the next part of the tutorial, we are going to get real contacts (when I say real contacts, I mean fake contacts — you know what I mean) from a real API: https://randomuser.me/. Feel free to browse the website and look at the response we will get back — this is where we will get our data to populate our components.

对于本教程的下一部分,我们将从真实的API: https//randomuser.me/中获得真实的联系人(当我说真实的联系人时,我的意思是假的联系人,您知道我的意思)。 随意浏览网站并查看我们将获得的答复-这是我们将获取数据以填充组件的地方。

Firstly, let’s create a state variable to hold the data we get back from the API. Remember, state is good for holding that that can change. Our contacts list can definitely change!

首先,让我们创建一个状态变量来保存从API返回的数据。 请记住,状态有利于保持可以改变的状态。 我们的联系人列表肯定可以更改!

In App.js, remove the contacts array add the following:

App.js中 ,删除联系人数组,添加以下内容:

const [contacts, setContacts] = useState([]);

Here, we’re doing here is creating a state object, and initialising it to an empty array. When we make the API call, we’ll update the state to contain a list of contacts. Since we named this state object contacts, our rendering logic within the JSX will look for this array instead (as opposed to the old contacts array we just deleted).

在这里,我们要做的是创建一个状态对象,并将其初始化为一个空数组。 进行API调用时,我们将更新状态以包含联系人列表。 由于我们将状态对象联系人命名为,因此JSX中的渲染逻辑将改为查找该数组(与我们刚刚删除的旧联系人数组相反)。

Next, let’s grab the data from the API. We’ll use the standard Fetch API. For now, we’ll log the data to the console. Add the following below the state object we just created:

接下来,让我们从API中获取数据。 我们将使用标准的Fetch API 。 现在,我们将数据记录到控制台。 在我们刚刚创建的状态对象下面添加以下内容:

fetch("https://randomuser.me/api/?results=3")
  .then(response => response.json())
  .then(data => {
    console.log(data);
  });

All we’re doing here is:

我们在这里所做的是:

  • Making a GET request to the randomuser API, asking for three results

    randomuser API发出GET请求,询问三个结果

  • Convert the response into JSON

    将响应转换为JSON

  • Logging the JSON to the console.

    JSON登录到控制台。

If you run this in the browser, you’ll notice the ContactCard components no longer render - thats fine, we haven’t saved any new data to state yet, and our state variable is currently empty. If you look at the console (in your browser dev tools) you’ll notice the response object is logged. Which will look something like this:

如果在浏览器中运行它,您会注意到ContactCard组件不再呈现-很好,我们还没有保存任何新数据来声明状态,并且state变量当前为空。 如果查看控制台(在浏览器开发工具中),您会注意到响应对象已记录。 看起来像这样:

You’ll see we have a results array, which has 3 objects. Each of these objects contain the details of a user (or a “Contact” in our case). This is similar to the contacts array we manually created ourselves in the previous section - just an array full of objects.

您将看到我们有一个结果数组,其中包含3个对象。 这些对象中的每一个都包含用户的详细信息(在本例中为“联系人”)。 这类似于我们在上一节中手动创建的contacts数组-只是一个充满对象的数组。

Let’s update our App components JSX to pick data from this object. Update the JSX like so:

让我们更新我们的App组件JSX,以从该对象中选择数据。 像这样更新JSX:

return (
  <>
    {contacts.map(contact => (
      <ContactCard
        avatar={contact.picture.large}
        name={contact.name.first + " " + contact.name.last}
        email={contact.email}
        age={contact.dob.age}
      />
    ))}
  </>
);

This works similar to what we had before:

这类似于我们以前的工作方式:

  • We are looping through the contacts variable (which, at the moment is an empty array)

    我们正在遍历contacts变量(目前是一个空数组)

  • When we eventually save the response to state (the next step) we look through each object in the array, for the appropriate things we need: in this case picture, name, email, and dob objects.

    当我们最终将响应保存到状态(下一步)时,我们将遍历数组中的每个对象,以查找所需的适当对象:在这种情况下, 图片,名称,电子邮件和dob对象。

Next we want to store the results array in state, so our JSX can loop over it (using the map() function we seen previously) and render some lovely ContactCards. Within our fetch function, add the call to setContacts(data.results) like so:

接下来,我们要在状态中存储结果数组,以便我们的JSX可以在其上循环(使用我们之前看到的map()函数)并呈现一些可爱的ContactCards 。 在我们的提取函数中,将调用添加到setContacts(data.results),如下所示:

fetch("https://randomuser.me/api/?results=3")
  .then(response => response.json())
  .then(data => {
    console.log(data);
    setContacts(data.results);
  });

Our App component now looks like this:

现在,我们的App组件如下所示:

//App.js
const App = () => {
  const [contacts, setContacts] = useState([]);

fetch("https://randomuser.me/api/?results=3")
  .then(response => response.json())
  .then(data => {
    console.log(data);
    setContacts(data.results);
  });

  return (
    <>
      {contacts.map(contact => (
        <ContactCard
          avatar={contact.picture.large}
          name={contact.name.first + " " + contact.name.last}
          email={contact.email}
          age={contact.dob.age}
        />
      ))}
    </>
  );
};

If you save this, and run it in the browser, you’ll see something like this:

如果保存并在浏览器中运行,您将看到类似以下内容:

You might be thinking, “WTF is going on? Everything is broken!”

您可能会想,“ WTF正在进行吗? 一切都被打破!”

Don’t panic just yet. (If you’re on a slower machine or just getting a bit freaked out, you can comment out the setContacts(data.results) line within the fetch function for now).

暂时不要惊慌。 (如果您使用的是较慢的计算机,或者只是有点害怕,可以暂时fetch函数中注释掉setContacts(data.results)行)。

What’s happening here is that we’re stuck in a bit of a loop:

这里发生的是我们陷入了一个循环:

  1. We make a call to fetch and get some data back

    我们拨打电话取回数据

  2. We then save this data to state

    然后,我们将这些数据保存到状态

  3. Remember, React does a re-render when the state changes

    记住, 状态改变时 React会重新渲染

  4. When the component re-renders, the fetch api call happens again, and sets the state

    当组件重新渲染时, 提取 api调用再次发生,并设置状态

  5. Since the state updated, the component re-renders again

    自状态更新以来,该组件再次重​​新渲染
  6. After the component re-renders, fetch is called again…

    重新渲染组件后,将再次调用提取…
  7. You get the idea

    你明白了

So how do we stop this? We have to delete everything and start again. Nah just kidding, don’t run away yet. We can fix this with another built in React Hook - useEffect.

那么我们如何制止这种情况呢? 我们必须删除所有内容,然后重新开始。 不,只是开玩笑,还没逃走。 我们可以用另一个内置的React Hook- useEffect来解决这个问题

引入useEffect (Introducing useEffect)

The useEffect hook is a special hook that runs a function. By default, the useEffect hook runs on every re-render. However, we can configure it to only run under certain condition, e.g. when a component mounts, or if a variable changes. The useEffect hook looks like this:

useEffect挂钩是运行函数的特殊挂钩。 默认情况下,useEffect挂钩在每次重新渲染时运行。 但是,我们可以将其配置为仅在特定条件下运行,例如,在安装组件时或变量更改时 。 useEffect挂钩如下所示:

useEffect(() => {
	// code to run 
});

This will run every time. If we want to specify “only run once” we pass in an empty array as a second argument like so.

这将每次运行。 如果要指定“仅运行一次”,则像这样将第二个参数传入一个空数组

useEffect(() => {
	// code to run 
},[]); //<-- notice the empty array

This is called a dependency array. When the dependency array is empty, this means the useEffect function will only run when the component loads for the first time. For additional re-renders, the useEffect function is skipped.

这称为依赖项数组 。 当依赖项数组为空时,这意味着useEffect函数将仅在组件首次加载时运行。 对于其他重新渲染,将跳过useEffect函数。

This is a perfect place to put our API call, as we only want to get the data once, when the component loads. Go ahead and place a **useEffect()**function into our App component, and move the fetch API call into the useEffect function. Our App component now looks like this:

这是放置API调用的理想场所,因为当组件加载时,我们只想获取一次数据。 继续,将** useEffect()**函数放入我们的App组件中,然后将fetch API调用移至useEffect函数中。 现在,我们的App组件如下所示:

//App.js
const App = () => {
  const [contacts, setContacts] = useState([]);

  useEffect(() => {
    fetch("https://randomuser.me/api/?results=3")
      .then(response => response.json())
      .then(data => {
        setContacts(data.results);
      });
  }, []);

  return (
    <>
      {contacts.map(contact => (
        <ContactCard
          avatar={contact.picture.large}
          name={contact.name.first + " " + contact.name.last}
          email={contact.email}
          age={contact.dob.age}
        />
      ))}
    </>
  );
};

Now, if you run the code in your browser, you should see 3 contact cards appear! Refresh the page to see another randomised list of contacts:

现在,如果在浏览器中运行代码,应该会看到3个联系卡! 刷新页面以查看另一个随机的联系人列表:

结论 (Conclusion)

Congrats! You just completed your first real-world app and laid the foundation to move on to more advanced topics.

恭喜! 您刚刚完成了自己的第一个实际应用,并奠定了继续学习更高级主题的基础。

Make sure to subscribe here to stay up to date with my latest React content, course discounts and early access, as well as some free stuff!

确保在这里订阅以获取我最新的React内容,课程折扣和抢先体验以及一些免费内容的最新信息!

Also don't forget to check out my new blog - www.jschris.com - where I'll be posting JavaScript/React related articles and tutorials!

另外,别忘了查看我的新博客-www.jschris.com-我将在其中发布JavaScript / React相关文章和教程!

翻译自: https://www.freecodecamp.org/news/getting-started-with-react-a-modern-project-based-guide-for-beginners-including-hooks-2/

react 生命挂钩

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用react-router-dom创建动态路由非常简单。我们可以使用Route组件来定义路由并在其中使用动态参数。以下是如何使用react-router-dom创建动态路由的步骤: 1. 安装react-router-dom:使用以下命令安装react-router-dom。 ``` npm install react-router-dom ``` 2. 在项目中导入所需的组件: ```javascript import React from "react"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; ``` 3. 创建路由并在其中使用动态参数: ```javascript <Router> <Switch> <Route exact path="/" component={Home} /> <<Route exact path="/users/:id" component={User} /> </Switch> </Router> ``` 上面的代码中,我们定义了一个具有动态参数的路由。用户可以通过访问URL `/users/:id` 来访问该路由。其中,`:id` 是一个动态参数,它将被替换为用户请求的实际值。 4. 在组件中获取动态参数: 在上面的代码中,我们定义了一个名为`User`的组件。我们可以在该组件中通过`props.match.params.id`来获取动态参数的值。以下是一个简单的示例: ```javascript import React from "react"; const User = (props) => { return <h1>User ID: {props.match.params.id}</h1>; }; export default User; ``` 在上面的代码中,我们使用`props.match.params.id`来获取动态参数的值,并将其显示在页面上。 这就是使用react-router-dom创建动态路由的基本步骤。你可以根据你的具体需求进行调整和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值